Object Comparison

I have a class that contains some string members, some double elements and some array objects.

I create two objects of this class, is there a simple and efficient way to compare these objects and say them equal? Any suggestions?

I know how to write a comparison function, but it will take a lot of time.

+8
c #
source share
5 answers

The only way to do this is to override bool Object.Equals(object other) to return true when the conditions for equality are met, and otherwise return false. You must also override int Object.GetHashCode() to return an int calculated from all the data that you consider when overriding Equals() .

Note that the contract for GetHashCode() indicates that the return value should be equal for two objects when Equals() will return true when comparing them. This means that return 0; is a valid implementation of GetHashCode() , but this will cause inefficiencies when objects of your class are used as dictionary keys or stored in a HashSet<T> .

The way to implement equality is as follows:

 public class Foo : IEquatable<Foo> { public bool Equals(Foo other) { if (other == null) return false; if (other == this) return true; // Same object reference. // Compare this to other and return true/false as appropriate. } public override bool Equals(Object other) { return Equals(other as Foo); } public override int GetHashCode() { // Compute and return hash code. } } 

An easy way to implement GetHashCode() is to XOR together the hash codes of all the data you consider for equality in Equals() . So, if, for example, the properties you are comparing for equality, string FirstName; string LastName; int Id; string FirstName; string LastName; int Id; , your implementation might look like this:

 public override int GetHashCode() { return (FirstName != null ? FirstName.GetHashCode() : 0) ^ (LastName != null ? LastName.GetHashCode() : 0) ^ Id; // Primitives of <= 4 bytes are their own hash codes } 

I usually do not redefine equality operators, since most of the time I deal with equality only for the purposes of dictionary keys or collections. I would only consider overriding equality operators if you are likely to make more comparisons by value than by reference, since it is syntactically less verbose. However, you must remember to change all places where you use == or != On your object (including when implementing Equals() !), To use Object.ReferenceEquals() , or to translate both operands to object . This nasty gotcha (which can cause infinite recursion in your equality test if you're not careful) is one of the main reasons I rarely override these operators.

+11
source share

The “right” way to do this in .NET is to implement the IEquatable interface for your class:

 public class SomeClass : IEquatable<SomeClass> { public string Name { get; set; } public double Value { get; set; } public int[] NumberList { get; set; } public bool Equals(SomeClass other) { // whatever your custom equality logic is return other.Name == Name && other.Value == Value && other.NumberList == NumberList; } } 

However, if you really want to do it right, that’s not all you need to do . You must also override the Equals (object, object) and GetHashCode (object) methods, so that no matter how your code code compares equality (perhaps in a dictionary or perhaps in some collection with a limited set of characters), your code, and not a reference code, type equality will be the determining factor:

 public class SomeClass : IEquatable<SomeClass> { public string Name { get; set; } public double Value { get; set; } public int[] NumberList { get; set; } /// <summary> /// Explicitly implemented IEquatable method. /// </summary> public bool IEquatable<SomeClass>.Equals(SomeClass other) { return other.Name == Name && other.Value == Value && other.NumberList == NumberList; } public override bool Equals(object obj) { var other = obj as SomeClass; if (other == null) return false; return ((IEquatable<SomeClass>)(this)).Equals(other); } public override int GetHashCode() { // Determine some consistent way of generating a hash code, such as... return Name.GetHashCode() ^ Value.GetHashCode() ^ NumberList.GetHashCode(); } } 
+9
source share

I just spent the whole day writing an extension method that cyclically reflects the properties of an object with various complex bits of logic to deal with a different type of property and actually brings it closer to good, and then at 16:55 it became clear to me that if you serialize two objects, you just need to compare two lines ... duh

So here is a simple way to decrypt a serializer that even works with dictionaries

  public static class TExtensions { public static string Serialize<T>(this T thisT) { var serializer = new DataContractSerializer(thisT.GetType()); using (var writer = new StringWriter()) using (var stm = new XmlTextWriter(writer)) { serializer.WriteObject(stm, thisT); return writer.ToString(); } } } 

Now your test can be as simple as

 Asset.AreEqual(objA.Serialise(), objB.Serialise()) 

Extensive testing has not yet been conducted, but it looks promising and, more importantly, simple. Anyway, another useful method for properly setting up your utility?

+5
source share

The best answer is to implement IEquatable for your class - this may not be the answer you want to hear, but the best way to implement value equivalence in .NET.

Another option would be to compute a unique hash of all members of your class and then compare the values ​​with them, but this is even more than writing a comparison function;)

+1
source share

Since these are objects, I assume that you have to override the Equals method for objects. Otherwise, the Equals method will only give you approval if both objects refer to the same object.

I know this is not the answer you want. But since there are few properties in your class, you can easily override this method.

+1
source share

Source: https://habr.com/ru/post/650115/


All Articles