So I have an interface, lets call it IInterface.
public interface IInterface : IEquatable<IInterface>
{
string Name { get; set; }
int Number { get; }
Task<bool> Update();
}
Then I try and implement the interface in Implementation.
public bool Equals(IInterface other)
{
if (other == null) return false;
return (this.Name.Equals(other.Name) && this.Number.Equals(other.Number));
}
public override int GetHashCode()
{
return this.Number.GetHashCode();
}
public override bool Equals(object obj)
{
var other = obj as IInterface ;
return other != null && Equals(other);
}
public static bool operator ==(Implementation left, IInterface right)
{
if (ReferenceEquals(left, right)) return true;
if (ReferenceEquals(left, null)) return false;
return left.Equals(right);
}
public static bool operator !=(Implementation left, IInterface right)
{
return !(left == right);
}
The problem I am running into is in a setter:
public IInterface MyIntf
{
get { return _myIntf; }
set
{
if (_myIntf == value) { return; }
_myIntf = value;
}
Intellisense is showing that the equality test there is testing the references only and treating both left and right as objects. I assume this is because there is no operator overload for ==(IInterface left, IInterface right). Of course, I cannot actually implement that function because == requires one of the sides to match the type of the implementing class. How does one properly make sure two interfaces can be checked for equality against each other?
Update
Got it, you cannot implement == for an interface. I will use Equals. Thanks everyone.
You should explicitly call Equals:
if (_myIntf != null && _myIntf.Equals(value)) { return; }
Implementing IEquatable<T> does not impact the == operator.
Use Equals instead of ==:
public IInterface MyIntf
{
get { return _myIntf; }
set
{
if (_myIntf.Equals(value)) { return; }
_myIntf = value;
}
}
Related
This question already has answers here:
IEquatable, how to implement this properly [duplicate]
(2 answers)
Closed 2 years ago.
I have a class heirarchy as follows:
public abstract class Issue
{
// some base properties
// these are not included in equality checks for deriving classes
// also not performing equality checks on this base class (it is abstract anyway)
}
public class IssueTypeA : Issue, IEquatable<IssueTypeA>
{
// some properties specific to this class
// these are the two for which equality comparison is performed
public string requirement { get; set; }
public string preamble { get; set; }
public bool Equals(IssueTypeA that)
{
// determine based on the values of the properties
// they must both be the same for equality
if ((this.requirement.Equals(that.requirement)) &&
(this.preamble.Equals(that.preamble)))
{
return true;
}
return false;
}
}
public class IssueTypeB : Issue, IEquatable<IssueTypeB>
{
// some properties specific to this class
public bool Equals(IssueTypeB that)
{
// determine based on the values of the properties
}
}
There is another class, intended to receive objects in the above heirarchy (except the base class, of course), and do some comparison operations with them:
public class Comparer<T> where T : Issue
{
// various comparison methods
public IEnumerable<T> getReferenceChangedIssues(IEnumerable<T> spreadsheetIssues, IEnumerable<T> downloadedIssues)
{
foreach (T spreadsheetRecord in T spreadsheetIssues)
{
foreach (T downloadedIssue in downloadedIssues)
{
// this is the point of failure
// there are cases in which this should be true, but it is not
if (spreadsheetRecord.Equals(downloadedIssue))
{
// the referenceChanged method works fine by itself
// it has been unit tested
if (spreadsheetRecord.referenceChanged(downloadedIssue))
yield return spreadsheetRecord;
}
}
}
}
}
Through unit testing and debugging, it's apparent that the custom Equals methods defined above are not being used correctly by Comparer. Why is this? It is also intended to include methods with some set operations in the future, which will need Equals.
When you implement IEquatable, you really need to override bool Equals(object) and GetHashCode. If you don't do that, things will break in weird ways. This was the stripped-down-est thing I could come up with. I think it should solve your issue (but I can't really tell without your comparison code). If folks point out issues, I'll fix up the code:
public abstract class Issue : IEquatable<Issue>
{
// possibly (not not necessarily) some base properties
// if they are included, make them part of the equality comparison and
// include them in the HashCode calculations
public bool Equals(Issue other)
{
if (other == null)
{
return false;
}
if (this.GetType() != other.GetType())
{
return false;
}
//test local properties and return true/false based on their values
return true;
}
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((Issue) obj);
}
}
public class IssueTypeA : Issue, IEquatable<IssueTypeA>
{
public string AName { get; set; } = "My A Name";
public int AValue { get; set; } = 42;
public bool Equals(IssueTypeA other)
{
if (!base.Equals(other))
{
return false;
}
return AName == other.AName && AValue == other.AValue;
}
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((IssueTypeA) obj);
}
//hash-codes need to be consistent once they are calculated - jump through some hoops
private int? _hashCodeValue = default;
public override int GetHashCode()
{
if (!_hashCodeValue.HasValue)
{
_hashCodeValue = $"{AName}{AValue}".GetHashCode();
}
return _hashCodeValue.Value;
}
}
public class IssueTypeB : Issue, IEquatable<IssueTypeB>
{
// some properties specific to this class
public string BName { get; set; } = "My B Name";
public int BValue { get; set; } = 84;
public bool Equals(IssueTypeB other)
{
if (!base.Equals(other))
{
return false;
}
//calculate equality based on local properties and return true/false
return BName == other.BName && BValue == other.BValue;
}
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((IssueTypeB) obj);
}
//hash-codes need to be consistent once they are calculated - jump through some hoops
private int? _hashCodeValue = default;
public override int GetHashCode()
{
if (!_hashCodeValue.HasValue)
{
_hashCodeValue = $"{BName}{BValue}".GetHashCode();
}
return _hashCodeValue.Value;
}
}
This is a better stab at a solution than the first pass. I check for equality based on properties local to each class. I also provide a GetHashCode implementation that is consistent (in the weird way that I believe GetHashCode requires - but in a way that drive Resharper nuts).
I have a class A, which holds a string property and overwrites Equals for equality testing.
public class A
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public override bool Equals(object obj)
{
return obj is A arg && (Prop == arg.Prop);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
I also have a class B which has a List<A> as property:
public class B
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
I wanna be able to compare to instances of B for equality and order.
How can I write the Equals method in B by not rewriting the same code I wrote in A?
Is there a way to reuse the A Equals?
Update: My first version assumed B is derived from A.
A.Equals:
If A is not sealed, obj is A ... can return a false positive if different types are compared. So the corrected version:
public override bool Equals(object obj)
{
return obj is A other
&& this.Prop == other.Prop
&& this.GetType() == other.GetType(); // not needed if A is sealed
}
A.GetHashCode:
base.GetHashCode will return different hash codes for different but equal instances, which is wrong. Derive the hashcode from self properties instead. If Prop acts like some ID, then simply return Prop.GetHashCode()
B.Equals:
public override bool Equals(object obj)
{
return obj is B other
&& this.Prop.SequenceEqual(other.Prop) // will re-use A.Equals
&& this.Prop.GetType() == other.Prop.GetType() // not needed if different IReadOnlyList types are ok
&& this.GetType() == other.GetType(); // not needed if B is sealed
}
B.GetHashCode:
You can aggregate the hash codes of A instances. Here I use a simple XOR but if the same items can often come in a different order you can come up with something more fancy.
return Prop.Aggregate(0, (h, i) => h ^ i.GetHashCode());
Implementing Equals for a list can be done by using the SequenceEquals method (from System.Linq namespace), which ensures that each item in one list equals the item at the same index in the other list.
One thing you might consider changing, however is your implementation of GetHashCode. This method should return the same number if two items are equal (though it's not guaranteed that two items with the same hash code are equal). Using base.GetHashCode() does not meet this requirement, since the base is object in this case; according to the documentation, "hash codes for reference types are computed by calling the Object.GetHashCode method of the base class, which computes a hash code based on an object's reference", so objects only return the same HashCode if they refer to the exact same object.
The HashCode should be based on the same properties used to determine equality, so in this case we want to use Prop.GetHashCode() for class A, and we want to aggregate the hashcode for all the items in Prop for class B.
Here's one way the classes could be refactored:
public class A : IEquatable<A>
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public bool Equals(A other)
{
if (other == null) return false;
return Prop == other.Prop;
}
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public override int GetHashCode()
{
return Prop.GetHashCode();
}
}
public class B : IEquatable<B>
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public bool Equals(B other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (Prop == null) return other.Prop == null;
return other.Prop != null && Prop.SequenceEqual(other.Prop);
}
public override bool Equals(object obj)
{
return Equals(obj as B);
}
public override int GetHashCode()
{
return Prop?.Aggregate(17,
(current, item) => current * 17 + item?.GetHashCode() ?? 0)
?? 0;
}
}
Linq contains a useful method to compare collections: SequenceEqual
public override bool Equals(object obj)
{
if (!(obj is B other))
{
return false;
}
if (this.Prop == null || other.Prop == null)
{
return false;
}
return this.Prop.SequenceEqual(other.Prop);
}
Also, implement IEquatable<T> when you override Equals.
How about something like this:
public override bool Equals(object obj)
{
if(!(obj is B))
{
return false;
}
var b = obj as B;
if(b.Prop.Count != this.Prop.Count)
{
return false;
}
for(var i =0; i < Prop.Count; i++)
{
if (!Prop.ElementAt(i).Equals(b.Prop.ElementAt(i)))
{
return false;
}
}
return true;
}
Why does this program print "not added" while I think it should print "added"?
using System;
using System.Collections.Generic;
class Element
{
public int id;
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
Element ret = new Element(d);
return ret;
}
public static bool operator ==(Element e1, Element e2)
{
return (e1.id == e2.id);
}
public static bool operator !=(Element e1, Element e2)
{
return !(e1.id == e2.id);
}
}
class MainClass
{
public static void Main(string[] args)
{
List<Element> element = new List<Element>();
element.Add(2);
if(element.Contains(2))
Console.WriteLine("added");
else
Console.WriteLine("not added");
}
}
The Contains method does not use the == operator. What is the problem?
The Contains method does not use the == operator
No - it uses Equals, which you haven't overridden... so you're getting the default behaviour of Equals, which is to check for reference identity instead. You should override Equals(object) and GetHashCode to be consistent with each other - and for sanity's sake, consistent with your == overload too.
I'd also recommend implementing IEquatable<Element>, which List<Element> will use in preference to Equals(object), as EqualityComparer<T>.Default picks it up appropriately.
Oh, and your operator overloads should handle null references, too.
I'd also strongly recommend using private fields instead of public ones, and making your type immutable - seal it and make id readonly. Implementing equality for mutable types can lead to odd situations. For example:
Dictionary<Element, string> dictionary = new Dictionary<Element, string>();
Element x = new Element(10);
dictionary[x] = "foo";
x.id = 100;
Console.WriteLine(dictionary[x]); // No such element!
This would happen because the hash code would change (at least under most implementations), so the hash table underlying the dictionary wouldn't be able to find even a reference to the same object that's already in there.
So your class would look something like this:
internal sealed class Element : IEquatable<Element>
{
private readonly int id;
public int Id { get { return id; } }
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
return new Element(d);
}
public static bool operator ==(Element e1, Element e2)
{
if (object.ReferenceEquals(e1, e2))
{
return true;
}
if (object.ReferenceEquals(e1, null) ||
object.ReferenceEquals(e2, null))
{
return false;
}
return e1.id == e2.id;
}
public static bool operator !=(Element e1, Element e2)
{
// Delegate...
return !(e1 == e2);
}
public bool Equals(Element other)
{
return this == other;
}
public override int GetHashCode()
{
return id;
}
public override bool Equals(object obj)
{
// Delegate...
return Equals(obj as Element);
}
}
(I'm not sure about the merit of the implicit conversion, by the way - I typically stay away from those, myself.)
The Contains method does not use the == operator. What is the problem?
That is correct.
This method [Contains] determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable.Equals method for T (the type of values in the list).
http://msdn.microsoft.com/en-us/library/bhkz42b3(v=vs.110).aspx
You need to override Equals() as well. Note when you overload Equals(), it is almost always correct to also override GetHashCode().
Override Equals and GetHashCode like:
class Element
{
public int id;
protected bool Equals(Element other)
{
return id == other.id;
}
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((Element) obj);
}
public override int GetHashCode()
{
return id; //or id.GetHashCode();
}
//..... rest of the class
See: List<T>.Contains Method
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable<T>.Equals method for T (the type of values in the list).
I have a Venue class, and a Coordinate class like so:
class Venue
{
string Name;
Coordinate coordinate;
}
class Coordinate
{
double latitute;
double longitude;
}
Now, I want to be able to select a venue based on a coordinate as follows:
List<Venue> venues = GetAllVenues();
var myVenue = venues.FirstOrDefault(venue=>venue.coordinate == myCoordinate);
I have an IEqualityComparer implementation, but the lambda expression does not have an overload which takes the IEqualityComparer as a parameter.
How do I use my equality comparer in a lambda expression?
EDIT:
My equality comparer looks like this:
class CoordinatesEqualityComparer:IEqualityComparer<Coordinate>
{
public bool Equals(Coordinate x, Coordinate y)
{
return x.RowIndex == y.RowIndex && x.ColumnIndex == y.ColumnIndex;
}
public int GetHashCode(Coordinate obj)
{
return obj.GetHashCode();
}
}
When I do a Union() operation, like so, it does not work correctly, even though coordinates in both lists are same.
List<Coordinates> coordinates;
CoordinatesEqualityComparer comparer;
coordinates.Union(someOtherListOfCoordinates, comparer);
However, when I do a union with itself, it works. What am I doing wrong? Does it have something to do with the GetHashCode() implementation?
Edit 2:
Fixing the GetHashCode() method seems to do the trick.
public int GetHashCode(Coordinates obj)
{
// Warning:Hack. Use two prime numbers to generate a hash based on two properties.
return obj.RowIndex.GetHashCode() * 7 + obj.ColumnIndex.GetHashCode() * 13 ;
}
Have you tried:
var ec = new YourEqualityComparer();
var myVenue = venues.FirstOrDefault(venue =>
ec.Equals(venue.coordinate, myCoordinate));
Of course, another approach would be to define the == operator for your Coordinate class and then you wouldn't need an IEqualityComparer:
class Coordinate
{
double latitude;
double longitude;
public override bool Equals(object obj)
{
return Object.ReferenceEquals(this, obj)) ||
this == (other as Coordinate);
}
public static bool operator ==(Coordinate l, Coordinate r)
{
return ((object)l == null && (object)r == null) ||
((object)l != null && (object)r != null) &&
// equality check including epsilons, edge cases, etc.
}
public static bool operator !=(Coordinate l, Coordinate r)
{
return !(l == r);
}
}
I would implement IEquatable<Coordinate>, override Equals(object), override GetHashCode(), and == != operators like this:
public class Coordinate : IEquatable<Coordinate>
{
public double Latitide { get; set; }
public double Longitude { get; set; }
public bool Equals(Coordinate other)
{
if (other == null)
{
return false;
}
else
{
return this.Latitide == other.Latitide && this.Longitude == other.Longitude;
}
}
public override bool Equals(object obj)
{
return this.Equals(obj as Coordinate);
}
public override int GetHashCode()
{
return this.Latitide.GetHashCode() ^ this.Longitude.GetHashCode();
}
public static bool operator ==(Coordinate value1, Coordinate value2)
{
if (!Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && !Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return true;
}
else
{
return value1.Latitide == value2.Latitide && value1.Longitude == value2.Longitude;
}
}
public static bool operator !=(Coordinate value1, Coordinate value2)
{
return !(value1 == value2);
}
}
Why does this program print "not added" while I think it should print "added"?
using System;
using System.Collections.Generic;
class Element
{
public int id;
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
Element ret = new Element(d);
return ret;
}
public static bool operator ==(Element e1, Element e2)
{
return (e1.id == e2.id);
}
public static bool operator !=(Element e1, Element e2)
{
return !(e1.id == e2.id);
}
}
class MainClass
{
public static void Main(string[] args)
{
List<Element> element = new List<Element>();
element.Add(2);
if(element.Contains(2))
Console.WriteLine("added");
else
Console.WriteLine("not added");
}
}
The Contains method does not use the == operator. What is the problem?
The Contains method does not use the == operator
No - it uses Equals, which you haven't overridden... so you're getting the default behaviour of Equals, which is to check for reference identity instead. You should override Equals(object) and GetHashCode to be consistent with each other - and for sanity's sake, consistent with your == overload too.
I'd also recommend implementing IEquatable<Element>, which List<Element> will use in preference to Equals(object), as EqualityComparer<T>.Default picks it up appropriately.
Oh, and your operator overloads should handle null references, too.
I'd also strongly recommend using private fields instead of public ones, and making your type immutable - seal it and make id readonly. Implementing equality for mutable types can lead to odd situations. For example:
Dictionary<Element, string> dictionary = new Dictionary<Element, string>();
Element x = new Element(10);
dictionary[x] = "foo";
x.id = 100;
Console.WriteLine(dictionary[x]); // No such element!
This would happen because the hash code would change (at least under most implementations), so the hash table underlying the dictionary wouldn't be able to find even a reference to the same object that's already in there.
So your class would look something like this:
internal sealed class Element : IEquatable<Element>
{
private readonly int id;
public int Id { get { return id; } }
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
return new Element(d);
}
public static bool operator ==(Element e1, Element e2)
{
if (object.ReferenceEquals(e1, e2))
{
return true;
}
if (object.ReferenceEquals(e1, null) ||
object.ReferenceEquals(e2, null))
{
return false;
}
return e1.id == e2.id;
}
public static bool operator !=(Element e1, Element e2)
{
// Delegate...
return !(e1 == e2);
}
public bool Equals(Element other)
{
return this == other;
}
public override int GetHashCode()
{
return id;
}
public override bool Equals(object obj)
{
// Delegate...
return Equals(obj as Element);
}
}
(I'm not sure about the merit of the implicit conversion, by the way - I typically stay away from those, myself.)
The Contains method does not use the == operator. What is the problem?
That is correct.
This method [Contains] determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable.Equals method for T (the type of values in the list).
http://msdn.microsoft.com/en-us/library/bhkz42b3(v=vs.110).aspx
You need to override Equals() as well. Note when you overload Equals(), it is almost always correct to also override GetHashCode().
Override Equals and GetHashCode like:
class Element
{
public int id;
protected bool Equals(Element other)
{
return id == other.id;
}
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((Element) obj);
}
public override int GetHashCode()
{
return id; //or id.GetHashCode();
}
//..... rest of the class
See: List<T>.Contains Method
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable<T>.Equals method for T (the type of values in the list).