I have a class like this
public class TestData
{
public string Name {get;set;}
public string type {get;set;}
public List<string> Members = new List<string>();
public void AddMembers(string[] members)
{
Members.AddRange(members);
}
}
I want to know if it is possible to directly compare to instances of this class to eachother and find out they are exactly the same? what is the mechanism? I am looking gor something like if(testData1 == testData2) //Do Something And if not, how to do so?
You should implement the IEquatable<T> interface on your class, which will allow you to define your equality-logic.
Actually, you should override the Equals method as well.
public class TestData : IEquatable<TestData>
{
public string Name {get;set;}
public string type {get;set;}
public List<string> Members = new List<string>();
public void AddMembers(string[] members)
{
Members.AddRange(members);
}
// Overriding Equals member method, which will call the IEquatable implementation
// if appropriate.
public override bool Equals( Object obj )
{
var other = obj as TestData;
if( other == null ) return false;
return Equals (other);
}
public override int GetHashCode()
{
// Provide own implementation
}
// This is the method that must be implemented to conform to the
// IEquatable contract
public bool Equals( TestData other )
{
if( other == null )
{
return false;
}
if( ReferenceEquals (this, other) )
{
return true;
}
// You can also use a specific StringComparer instead of EqualityComparer<string>
// Check out the specific implementations (StringComparer.CurrentCulture, e.a.).
if( EqualityComparer<string>.Default.Compare (Name, other.Name) == false )
{
return false;
}
...
// To compare the members array, you could perhaps use the
// [SequenceEquals][2] method. But, be aware that [] {"a", "b"} will not
// be considerd equal as [] {"b", "a"}
return true;
}
}
One way of doing it is to implement IEquatable<T>
public class TestData : IEquatable<TestData>
{
public string Name {get;set;}
public string type {get;set;}
public List<string> Members = new List<string>();
public void AddMembers(string[] members)
{
Members.AddRange(members);
}
public bool Equals(TestData other)
{
if (this.Name != other.Name) return false;
if (this.type != other.type) return false;
// TODO: Compare Members and return false if not the same
return true;
}
}
if (testData1.Equals(testData2))
// classes are the same
You can also just override the Equals(object) method (from System.Object), if you do this you should also override GetHashCode see here
There are three ways objects of some reference type T can be compared to each other:
With the object.Equals method
With an implementation of IEquatable<T>.Equals (only for types that implement IEquatable<T>)
With the comparison operator ==
Furthermore, there are two possibilities for each of these cases:
The static type of the objects being compared is T (or some other base of T)
The static type of the objects being compared is object
The rules you absolutely need to know are:
The default for both Equals and operator== is to test for reference equality
Implementations of Equals will work correctly no matter what the static type of the objects being compared is
IEquatable<T>.Equals should always behave the same as object.Equals, but if the static type of the objects is T it will offer slightly better performance
So what does all of this mean in practice?
As a rule of thumb you should use Equals to check for equality (overriding object.Equals as necessary) and implement IEquatable<T> as well to provide slightly better performance. In this case object.Equals should be implemented in terms of IEquatable<T>.Equals.
For some specific types (such as System.String) it's also acceptable to use operator==, although you have to be careful not to make "polymorphic comparisons". The Equals methods, on the other hand, will work correctly even if you do make such comparisons.
You can see an example of polymorphic comparison and why it can be a problem here.
Finally, never forget that if you override object.Equals you must also override object.GetHashCode accordingly.
I see many good answers here but just in case you want the comparison to work like
if(testData1 == testData2) // DoSomething
instead of using Equals function you can override == and != operators:
public static bool operator == (TestData left, TestData right)
{
bool comparison = true; //Make the desired comparison
return comparison;
}
public static bool operator != (TestData left, TestData right)
{
return !(left == right);
}
You can override the equals method and inside it manually compare the objects
Also take a look at Guidelines for Overloading Equals() and Operator ==
You will need to define the rules that make object A equal to object B and then override the Equals operator for this type.
http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
First of all equality is difficult to define and only you can define as to what equality means for you
Does it means members have same value
Or they are pointing to same location.
Here is a discussion and an answer here
What is "Best Practice" For Comparing Two Instances of a Reference Type?
Implement the IEquatable<T> interface. This defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances. More information here:
http://msdn.microsoft.com/en-us/library/ms131187.aspx
Related
I'm comparing two objects of type Triangle and apparently they are deemed equal (I implemented my custom GetHaschCode as well as Equal method and operator).
List<Triangle> triangles = ...;
bool same = triangles[0] == triangles[1];
// same is true
However, when I go Distinct() on that list, it keeps all the elements (which sound to me like it's comparing by reference and not by my custom conditions). Is it so and what can I do about it?
int countBefore = triangles.Count();
int countAfter = triangles.Distinct().Count();
bool same = countBefore == countAfter;
// same is true, again
I'm missing something fairly obvious, am I not?
You can do this in one of two ways...
Either as Andrew says implement IEquatable
public class Triangle : IEquatable<Triangle>
{
bool IEquatable<Triangle>.Equals(Triangle other)
{
return Equals(other);
}
public override bool Equals(object obj)
{
//...
}
public override int GetHashCode()
{
//...
}
}
Or you could create another class that implements IEqualityComparer(T) and pass that into the Distinct method call.
public class TriangleComparer : IEqualityComparer<Triangle>
{
public bool Equals(Triangle x, Triangle y)
{
return x.Equals(y);
}
public int GetHashCode(Triangle obj)
{
return obj.GetHashCode();
}
}
You need to implement the IEquatable(T) interface in your Triangle class.
From the Enumerable.Distinct() documentation:
The default equality comparer, Default, is used to compare values of
the types that implement the IEquatable generic interface. To
compare a custom data type, you need to implement this interface and
provide your own GetHashCode and Equals methods for the type.
I am trying to make several operations use the same comparison method but I have been unable to get all of them to use it. In the following code I put a breakpoint to check which of the operations are using it. My results show that while List.Contains() does use it, List.Distinct() and "==" do not.
How can I make all 3 of them use my equality comparison?
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
List<TestObject> list1 = new List<TestObject>();
list1.Add(new TestObject("test1"));
list1.Add(new TestObject("test1"));
List<TestObject> list2 = list1.Distinct().ToList();
if (list1[0] == list1[1]) { }
if (list2.Contains(list1[0])){ }
}
}
class TestObject: IEquatable<TestObject>
{
string name;
public TestObject(string name)
{
this.name = name;
}
public bool Equals(TestObject other)
{
return this.name == other.name;
}
}
}
Thank you
For IEnumerable<T>, Distinct uses the default IEquatableComparer<T> comparer (unless you pass your own comparer). Internally this relies on GetHashCode to perform equality checks, where as Contains uses Equals hence why they don't yield the same results.
It's generally recommended you override both Equals and GetHashCode when implementing your own custom equality checks anyway, see Guidelines for Overloading Equals() and == Operator.
== is normally used to determine whether two references are the same. If you want to change this behavior for your class then you need to override the == operator as per the instructions here:
https://msdn.microsoft.com/en-US/library/ms173147(v=vs.80).aspx
I have a class that implements an interface, such as this:
interface IInterface
{
string PropA { get; }
string PropB { get; }
}
class AClass : IInterface
{
string PropA { get; protected set; }
string PropB { get; protected set; }
}
Equality is determined based on PropA and PropB. When overriding the Equals method for AClass, should I attempt to cast obj to AClass, like this:
public override bool Equals(object obj)
{
AClass other = obj as AClass;
return other != null
&& AClass.PropA == other.PropA
&& AClass.PropB == PropB;
}
Or should I attempt to cast obj to IInterface, like this:
public override bool Equals(object obj)
{
IInterface other = obj as IInterface;
return other != null
&& AClass.PropA == other.PropA
&& AClass.PropB == PropB;
}
You could do whichever you want. The two aren't the same, functionally, but which is "right" for you is something that we can't answer. If I have a BClass class that implements the same interface, and it has the same values for both properties, should it be equal to your AClass object? If yes, do the latter, if not, do the former.
Personally, I would find the latter concerning. Generally I find that if a class is going to implement its own personal definition of equality, other classes shouldn't be equal to it. One main reason is that it's preferable if equality is symetric. That is to say aclass.Equals(bclass) should return the same thing as bclass.Equals(aclass). Getting that behavior when you don't restrict equality to the same type is...hard. It requires cooperation of all related classes.
If you have some compelling reason to be comparing IInterface implementations in which they might be different underlying classes but still both be "equal", I'd personally prefer to create an IEqualityComparer<IInterface> that defines equality for that interface. This would the be separate from the definition of equality for either of the two implementing classes.
Decide how you need it to function.
Resharper implementation:
class AClass : IInterface, IEquatable<AClass>
{
public bool Equals(AClass other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(this.PropA, other.PropA) && string.Equals(this.PropB, other.PropB);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof (AClass)) return false;
return Equals((AClass)obj);
}
public override int GetHashCode()
{
unchecked
{
return ((this.PropA != null ? this.PropA.GetHashCode() : 0) * 397) ^ (this.PropB != null ? this.PropB.GetHashCode() : 0);
}
}
public string PropA { get; protected set; }
public string PropB { get; protected set; }
}
If the purpose of the interface is to hide from consumers the fact that two equivalent objects might be of different classes, it may be a good idea to define a struct which holds a single private field of that interface type and chains to the appropriate methods of the interfaces. Use of such a struct should generally be essentially as efficient as using a variable of the interface type (the main exception would be if the struct ends up being boxed), but would shield client code from seeing the actual type of thing implementing the interface.
For example, one might have a interfaces IReadableMatrix<T> and IImmutableMatrix<T>, and corresponding structures ReadableMatrix<T> and ImmutableMatrix<T> with read-only members int Height, int Width, and T this[int row, int column], and ImmutableMatrix<T> AsImmutable();. Code which uses an ImmutableMatrix<double> shouldn't care how it's stored; it would be entirely possible that two instances of ImmutableMatrix might hold references to different implementations of IImmutableMatrix<T> which report identical content in every cell, but stored things entirely differently. One might be an instance of ArrayBackedMatrix<double>, which holds a 12x12 array that happens to hold zeroes in every element other than those on the diagonal, while the other might be a DiagonalMatrix<double>, and use a 12-item array that only stores things on the diagonal (and returns zero in response to a request for any other element). The use of different types to store the array data should be an implementation detail and not exposed to the client.
One slight detail of using a struct to wrap the arrays is that reference-type fields of a default-value structure will be null, but the structure itself will not. It may thus be desirable to either have the struct implement an IsNull property which returns true if the backing field is null, or else have the other struct members check whether the backing field is null and, if so, behave as an empty 0x0 matrix.
I've implemented every function that MSDN says is necessary, plus some additional comparison interfaces - nothing seems to work. Following is code (optimized for LinqPad).
The resulting output is all 4 items, not 2 like I expect.
Please don't post work arounds as answers - I want to know how Distinct works
void Main()
{
List<NameClass> results = new List<NameClass>();
results.Add(new NameClass("hello"));
results.Add(new NameClass("hello"));
results.Add(new NameClass("55"));
results.Add(new NameClass("55"));
results.Distinct().Dump();
}
// Define other methods and classes here
public class NameClass : Object
, IEquatable<NameClass>
, IComparer<NameClass>
, IComparable<NameClass>
, IEqualityComparer<NameClass>
, IEqualityComparer
, IComparable
{
public NameClass(string name)
{
Name = name;
}
public string Name { get; private set; }
public int Compare(NameClass x, NameClass y)
{
return String.Compare(x.Name, y.Name);
}
public int CompareTo(NameClass other)
{
return String.Compare(Name, other.Name);
}
public bool Equals(NameClass x, NameClass y)
{
return (0 == Compare(x, y));
}
public bool Equals(NameClass other)
{
return (0 == CompareTo(other));
}
public int GetHashCode(NameClass obj)
{
return obj.Name.GetHashCode();
}
public new int GetHashCode()
{
return Name.GetHashCode();
}
public new bool Equals(object a)
{
var x = a as NameClass;
if (null == x) { return false; }
return Equals(x);
}
public new bool Equals(object a, object b)
{
if (null == a && null == b) { return true; }
if (null == a && null != b) { return false; }
if (null != a && null == b) { return false; }
var x = a as NameClass;
var y = b as NameClass;
if (null == x && null == y) { return true; }
if (null == x && null != y) { return false; }
if (null != x && null == y) { return false; }
return x.Equals(y);
}
public int GetHashCode(object obj)
{
if (null == obj) { return 0; }
var x = obj as NameClass;
if (null != x) { return x.GetHashCode(); }
return obj.GetHashCode();
}
public int CompareTo(object obj)
{
if (obj == null) return 1;
NameClass x = obj as NameClass;
if (x == null)
{
throw new ArgumentException("Object is not a NameClass");
}
return CompareTo(x);
}
}
How Distinct works:
There is at least no implementation of Object.GetHashCode() which is used for initial comparison of objects: basic version of Distinct compares (actually puts in dictionary) by Object.GetHashCode first, than if hash code matches by Object.Equals.
To be precise Enumerable.Distinct(this IEnumerable source) uses EqualityComparer<NameClass>.Default to finally check for equality (note that if hash codes don't match it will not reach that portion of the comparison which is why your sample does not work).
The default equality comparer, Default, is used to compare values of the types that implement the IEquatable generic interface.
EqualityComparer.Default in turn actually allows to use class without IEquatable<T> at all falling back directly to Object.Equals:
The Default property checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer that uses that implementation. Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
So for basic Distinct to work you just need correct version of Equals/GetHashCode. IEquatable is optional, but must match behavior of GetHashCode in the class.
How to fix:
Your sample have public new int GetHashCode() method, which likely should be public override int GetHashCode() (Same for Equals).
Note that public new int... does not mean "override", but instead "create new version of the method that hides old one". It does not impact callers that call method via pointer to parent object.
Personally I think new should rarely be used in defining methods. Some suggestions when it is useful are covered in Usecases for method hiding using new.
You don't have to implement any interface, just GetHashCode and Equals methods correctly:
public class NameClass
{
public NameClass(string name)
{
Name = name;
}
public string Name { get; private set; }
public override bool Equals(object obj)
{
var other = obj as NameClass;
return other != null && other.Name == this.Name;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
Enumerable.Distinct<TSource> Method:
It uses the default equality comparer, Default, to compare values.
EqualityComparer.Default:
The Default property checks whether type T implements the System.IEquatable<T> interface and, if so, returns an EqualityComparer<T> that uses that implementation. Otherwise, it returns an EqualityComparer<T> that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
IEquatable<T> Interface:
If you implement IEquatable<T>, you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable<T>.Equals method.
Overriding methods:
The override modifier is required to extend or modify the abstract or virtual implementation of an inherited method, property, indexer, or event.
So your code should look like this:
public class NameClass : IEquatable<NameClass>
{
public NameClass(string name)
{
Name = name;
}
public string Name { get; private set; }
// implement IEquatable<NameClass>
public bool Equals(NameClass other)
{
return (other != null) && (Name == other.Name);
}
// override Object.Equals(Object)
public override bool Equals(object obj)
{
return Equals(obj as NameClass);
}
// override Object.GetHashCode()
public override GetHashCode()
{
return Name.GetHashCode();
}
}
So, first off, Distinct will, as per it's documentation, use EqualityComparer<T>.Default to compare objects if no custom equality comparer is provided (you provided none).
EqualityComparer<T>.Default, as per its documentation, will look to see if the object implements IEquatable<T>, if it does it will use that implementation of Equals.
Regardless of whether or not the type implements IEquatable<T>, EqualityComparer<T>.Default will use the object.GetHashCode method to get the has code of the object. IEquatable<T>, unfortunately, does not force you to also override the object's GetHashCode implementation, and in your case, while you do implement IEquatable<T>, your code does not override the object's GetHashCode implementation.
As a result of this Distinct is actually using the proper Equals method for your type, but it's using the wrong GetHashCode method. Whenever you're hashing objects and that type has an Equals and GetHashCode implementation that's out of sync problems ensue. What's happening is that in whatever hash based collection it's sending the two "equal" objects to different buckets, so they never even get to the point where their Equals methods are called on each other. If you happened to get lucky and there was a hash collection and the objects were coincidentally sent to the same bucket, then, since the Equals method is what you intended it would actually work, but the odds of that happening are...very low. (In this specific case, about 2/2147483647, or
9.3e-10.
While you do provide a new GetHashCode method in NameClass, it is hiding the object implementation, not overriding it. If you change your GetHashCode implementation to use override rather than new then your code will work.
I just realized I messed up my sample code - my class derives from DependencyObject, not Object. I can't override thew GetHashCode or Equals functions because the DependencyObject class is sealed.
I have HashSet of my custom class:
public class Vertex
{
public string Name;
public override bool Equals(object obj)
{
var vert = obj as Vertex;
if (vert !=null)
{
return Name.Equals(vert.Name, StringComparison.InvariantCulture);
}
return false;
}
}
And now I have tow hashsets
HashSet<Vertex> hashSet1 = new HashSet<Vertex>();
HashSet<Vertex> hashSet1 = new HashSet<Vertex>();
And now I'd like to have in hashSet1 only Vertexes that are not in hashSet2
So I use ExceptWith method
hashSet1.ExceptWith(hashSet2);
But this doesn't work.
I suppose that this doesn't work because I have complex type.
So the question is: is there some interface required to be implemented in Vertex class to make this thing work?
I know that while creation of HashSet I can pass a EqualityComparer but it seems to me that it would be more elegant to implement some comparing interface method in Vertex class.
Is it possible or I just doesn't understand sth?
Thanks.
When overriding Equals you should also override GetHashCode. HashSet (and other hashing structures like Dictionary) will first calculate a hash code for your objects to locate them in tne structure before comparing elements with Equals.
public override int GetHashCode()
{
return StringComparer.InvariantCulture.GetHashCode(this.Name);
}
You don't have to implement any interface (although IEquatable<T>) is encouraged. When you create a hash-set without specifying an equality-comparer, it defaults to using EqualityComparer<T>.Default, which asks the objects themselves to compare themselves to each other (special-casing null references).
However, in your case, your equality contract is broken since you haven't overriden GetHashCode. Here's how I would fix your type:
public class Vertex : IEquatable<Vertex>
{
public string Name { get; private set; }
public Vertex(string name)
{
Name = name;
}
public override int GetHashCode()
{
return StringComparer.InvariantCulture.GetHashCode(Name);
}
public override bool Equals(object obj)
{
return Equals(obj as Vertex);
}
public bool Equals(Vertex obj)
{
return obj != null && StringComparer.InvariantCulture.Equals(Name, obj.Name);
}
}
Would you mind overriding the .GetHashCode()too?
Here's the reference.
You have to override GetHashCode with Equals overriding.
Object.Equals Method:
Types that override Equals(Object) must also override GetHashCode; otherwise, hash tables might not work correctly.