Have the object model as shown below with HashSets:
When I try to find the matching set with the below statement does not work.
Could someone please suggest what am I missing here?
Would HashSet.CreateSetComparer solve the problem, if so could you please suggest how to use it?
HashSet Overlaps Statement:
var requirementSets = new HashSet<RequirementSet>();
// requirementSets has some data.
RequirementSet matchingSet = requirementSets.FirstOrDefault(e => e.RequirementOption s.Overlaps(lineItemRequirementSet.RequirementOptions));
Object Model:
public class RequirementSet : IEquatable<RequirementSet>
{
public ISet<RequirementOption> RequirementOptions { get; } = new HashSet<RequirementOption>();
public bool Equals(RequirementSet other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Equals(RequirementOptions, other.RequirementOptions);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((RequirementSet) obj);
}
public override int GetHashCode()
{
return RequirementOptions != null ? RequirementOptions.GetHashCode() : 0;
}
}
public class RequirementOption : IEquatable<RequirementOption>
{
public ISet<Requirement> Requirements { get; } = new HashSet<Requirement>();
public bool Equals(RequirementOption other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Equals(Requirements, other.Requirements);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((RequirementOption) obj);
}
public override int GetHashCode()
{
return Requirements != null ? Requirements.GetHashCode() : 0;
}
}
public class Requirement : IEquatable<Requirement>
{
public string Model {get; set;}
public bool Equals(Requirement other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ModelName == other.ModelName;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((Requirement) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = ModelName != null ? ModelName.GetHashCode();
return hashCode;
}
}
}
Related
I am receiving KeyNotFoundException whenever I try to access the key in dictionary.
I have a PricingRules class which has a dictionary:
public class PricingRules
{
Dictionary<ItemCode, Money> pricing_rules;
public PricingRules()
{
pricing_rules = new Dictionary<ItemCode, Money>();
pricing_rules.Add(new ItemCode("A"), new Money(50));
pricing_rules.Add(new ItemCode("B"), new Money(30));
pricing_rules.Add(new ItemCode("C"), new Money(20));
pricing_rules.Add(new ItemCode("D"), new Money(15));
}
public void itemScanned(ItemCode itemCode, Money amount)
{
amount.Add(pricing_rules[itemCode]);
}
public Money AmountForItem(ItemCode itemCode)
{
return pricing_rules[itemCode];
}
}
The key in the dictionary is of type ItemCode:
public class ItemCode
{
private readonly string itemCode;
public ItemCode(string itemCode)
{
this.itemCode = itemCode;
}
public override int GetHashCode()
{
return itemCode.GetHashCode();
}
}
and the value is of type Money:
public class Money
{
private int amount;
public Money(int amount)
{
this.amount = amount;
}
public override bool Equals(object obj)
{
Money money = (Money)obj;
return this.amount == money.amount;
}
public void Add(object obj)
{
Money money = (Money)obj;
this.amount += money.amount;
}
public override int GetHashCode()
{
return amount.GetHashCode();
}
}
I have tried overriding the GetHashCode() function to return the HashCode of the primitive type in the class but it still is giving KeyNotFoundException
The test I have written is:
public class PricingRulesShould
{
[Fact]
void ReturnValueFiftyWhenKeyIsA()
{
Money expected = new Money(50);
PricingRules pr = new PricingRules();
ItemCode itemcode = new ItemCode("A");
Money actual = pr.AmountForItem(itemcode);
Assert.Equal(expected, actual);
}
}
When Dictionary accesses its elements, it looks for the equality of keys.
Since the ItemCode is not a primitive type, when you compare new ItemCode("A") == new ItemCode("A") you should get false as a result, because they are different instances with identical contents.
What you can do is to implement IEquatable<ItemCode> by the ItemCode class:
public class ItemCode : IEquatable<ItemCode>
{
private readonly string itemCode;
public ItemCode(string itemCode)
{
this.itemCode = itemCode;
}
public override int GetHashCode()
{
return itemCode != null ? itemCode.GetHashCode() : 0;
}
public bool Equals(ItemCode other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(itemCode, other.itemCode);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
return obj is ItemCode ic && Equals(ic);
}
}
Lets say I define the following abstract class:
public abstract class ValueEquality<T> : IEquatable<T>
where T : ValueEquality<T>
{
public override bool Equals(object obj)
{
return Equals(obj as T);
}
public static bool operator ==(ValueEquality<T> lhs, object rhs)
{
if (ReferenceEquals(lhs, rhs))
{
return true;
}
else if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
{
return false;
}
else
{
return lhs.Equals(rhs);
}
}
public static bool operator !=(ValueEquality<T> lhs, object rhs)
{
return !(lhs == rhs);
}
public bool Equals(T other)
{
return other != null && EqualNoNull(other);
}
public abstract override int GetHashCode();
public abstract bool EqualNoNull(T other);
}
And then create a class C as follows:
public class C : MyEquatable<C>
{
public override bool EqualsNoNull(C other)
{
...
}
public override int GetHashCode()
{
...
}
}
If I then have the code:
C x1;
C x2;
bool equal = x1 == x2;
Will this end up calling the equals method in C? Are there any gotchas with this approach?
Edit: fixed some issues in code raised by answers.
This code will do infinite loop in:
public override bool Equals(object obj)
{
try
{
T otherT = (T) obj;
return Equals(this, otherT);
}
catch (InvalidCastException)
{
return false;
}
}
It will call Equals(object obj) again and again. Right implementation:
public abstract class MyEquatable<T> : IEquatable<T>
where T : MyEquatable<T>
{
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return this.Equals((MyEquatable<T>)obj);
}
protected bool Equals(MyEquatable<T> other)
{
return this.Equals(other as T);
}
public static bool operator ==(MyEquatable<T> lhs, object rhs)
{
return Equals(lhs, rhs);
}
public static bool operator !=(MyEquatable<T> lhs, object rhs)
{
return Equals(lhs, rhs);
}
public abstract bool Equals(T other);
public abstract override int GetHashCode();
}
x1 == x2 will call operator == of MyEquatable, that will call Equals(object obj). Finally, it calls Equals(T other) overridden in C class
Another implementation which follows what is usually advised in documentation
public abstract class MyEquatable<T> : IEquatable<T>
where T : MyEquatable<T> {
public override bool Equals(object obj) {
if (ReferenceEquals(obj, null) || obj.GetType() != GetType())
return false;
var valueObject = obj as T; //Note the cast
if (ReferenceEquals(valueObject, null))
return false;
return Equals(valueObject); //Calls Equals(T other)
}
public abstract bool Equals(T other);
public abstract override int GetHashCode();
public static bool operator ==(MyEquatable<T> left, MyEquatable<T> right) {
if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
return true;
if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
return false;
return left.Equals(right);
}
public static bool operator !=(MyEquatable<T> left, MyEquatable<T> right) {
return !(left == right);
}
}
I have got a class called Team.
class Team
{
public Team(string name)
{
this.Name = name;
this.Wins = 0;
this.Opponents = new HashSet<Team>();
}
public string Name { get; set; }
public int Wins { get; set; }
public HashSet<Team> Opponents { get; set; }
}
I get a Stackoverflow exception whenever i try to add an existing team with a single opponent in another team's HashSet that has zero Opponents guestTeam.Opponents.Add(homeTeam);
Here hometeam has a single opponents in Opponents while guestTeam.Opponents is still empty.
Its a small test app. Stacktrace's framecount shows 3.
Any ideas why would i get such an exception thrown?
I admit, I can't reproduce error. personally I could go into properly implement of
: IEquatable<Team>
And then:
public bool Equals(Team other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(this.Name, other.Name) && Equals(this.Opponents, other.Opponents);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Team)obj);
}
public override int GetHashCode()
{
unchecked
{
return ((this.Name != null ? this.Name.GetHashCode() : 0) * 397) ^ (this.Opponents != null ? this.Opponents.GetHashCode() : 0);
}
}
public static bool operator ==(Team left, Team right)
{
return Equals(left, right);
}
public static bool operator !=(Team left, Team right)
{
return !Equals(left, right);
}
Of course I am cannot reproduce that so it's just shot.
I have following value
public class Identification : IEquatable<Identification>
{
public int Id { get; set; }
public byte[] FileContent { get; set; }
public int ProjectId { get; set; }
}
Which I generated equality members for with resharper
public bool Equals(Identification other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Id == other.Id && Equals(FileContent, other.FileContent) && ProjectId == other.ProjectId;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Identification) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = Id;
hashCode = (hashCode*397) ^ (FileContent != null ? FileContent.GetHashCode() : 0);
hashCode = (hashCode*397) ^ ProjectId;
return hashCode;
}
}
public static bool operator ==(Identification left, Identification right)
{
return Equals(left, right);
}
public static bool operator !=(Identification left, Identification right)
{
return !Equals(left, right);
}
But when I want to unit test it's equality before and after returning from the repository it fails. Despite having the exact same properties in the failure message.
var identification = fixture
.Build<Identification>()
.With(x => x.ProjectId, projet.Id)
.Create();
await repository.CreateIdentification(identification);
var returned = await repository.GetIdentification(identification.Id);
Assert.Equal() Failure
Expected: Identification { FileContent = [56, 192, 243], Id = 8, ProjectId = 42 }
Actual: Identification { FileContent = [56, 192, 243], Id = 8, ProjectId = 42 }
I'm using Npgsql with Dapper if it matters.
You should use Enumerable.SequenceEqual for arrays which checks for:
Both arrays are null or both arrays are not null.
Both arrays have same Length.
Corresponging items are equal to one another.
Something like this
public bool Equals(Identification other)
{
if (ReferenceEquals(null, other))
return false;
else if (ReferenceEquals(this, other))
return true;
return Id == other.Id &&
ProjectId == other.ProjectId &&
Enumerable.SequenceEqual(FileContent, other.FileContent);
}
Since Enumerable.SequenceEqual can well be time cosuming I've shifted it to the end of the comparison (there's no need to check arrays if, say, ProjectId are failed to be equal)
I have simple class defining 2d line:
public class Line {
public double X1 { get; set; }
public double Y1 { get; set; }
public double X2 { get; set; }
public double Y2 { get; set; }
}
My primary goal is to get different lines from List using .Distinct(). In my case two lines are equal if theirs coordinates are equal regardless direction (line 1,2 -> 3,4 equals to 3,4 -> 1,2). I going to implement Equals like:
public override bool Equals(object obj) {
if (obj as Line == null) { return false; }
var second = (Line)obj;
if (this.X1 != second.X1 && this.X1 != second.X2) { return false; }
if (this.Y1 != second.Y1 && this.Y1 != second.Y2) { return false; }
if (this.X2 != second.X2 && this.X2 != second.X1) { return false; }
if (this.Y2 != second.Y2 && this.Y2 != second.Y1) { return false; }
return true;
}
but I have no idea how to implement GetHashCode (as I understand it's necessary to make it in case of using Distinct())
This becomes a bit easier if you first define a Point, then define your Line in terms of 2 Points.
Now, to calculate a reliable (but unaffected by direction) hash of a Line, make sure you order your points consistently when calculating the hash.
Putting this all together into a complete implementation (which also covers operator == and !=):
public class Point
{
public double X { get; set; }
public double Y { get; set; }
protected bool Equals(Point other)
{
return X.Equals(other.X) && Y.Equals(other.Y);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Point) obj);
}
public override int GetHashCode()
{
unchecked
{
return (X.GetHashCode()*397) + Y.GetHashCode();
}
}
public static bool operator ==(Point left, Point right)
{
return Equals(left, right);
}
public static bool operator !=(Point left, Point right)
{
return !Equals(left, right);
}
}
public class Line
{
public Point Point1 { get; set; }
public Point Point2 { get; set; }
protected bool Equals(Line other)
{
return Equals(Point1, other.Point1) && Equals(Point2, other.Point2)
|| Equals(Point1, other.Point2) && Equals(Point2, other.Point1);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Line) obj);
}
public override int GetHashCode()
{
unchecked
{
var orderedPoints =
new[] {Point1, Point2}.OrderBy(p => p != null ? p.X : 0)
.ThenBy(p => p != null ? p.Y : 0).ToList();
var p1 = orderedPoints[0];
var p2 = orderedPoints[1];
return ((p1 != null ? p1.GetHashCode() : 0)*397)
+ (p2 != null ? p2.GetHashCode() : 0);
}
}
public static bool operator ==(Line left, Line right)
{
return Equals(left, right);
}
public static bool operator !=(Line left, Line right)
{
return !Equals(left, right);
}
}