Equality comparing objects - c#

I have code like this:
public bool AreSame(CreditProposal creditProposal)
{
if (!ContractingParty.Equals(creditProposal.ContractingParty))
return false;
if (!UltimateParent.Equals(creditProposal.UltimateParent))
return false;
if (!Rebound.Equals(creditProposal.Rebound))
return false;
if (!ContactPerson.Equals(creditProposal.ContactPerson))
return false;
if (!DateOfVisit.Equals(creditProposal.DateOfVisit))
return false;
.... and so on 10 more times
Is there a way to do this more concise? Or will that mean I get into reflection hell?

Override Equals method.
Check this on MSDN
And notice If you implement ==, you must implement !=.

The instinctive way to handle this situation is to override the Object.Equals(Object) method and implement IEquatable<T> for your type.
However, overriding Object.Equals will prompt you to also override Object.GetHashCode(), which is a lot harder to do correctly. Most notably, GetHashCode() must return the same value each time it is called on the same instance, and must return the same value for two objects which are considered equal. If your type is mutable, this becomes a real pain. (In fact, GetHashCode() is so difficult to implement correctly, there's a whole tag for it on StackOverflow: https://stackoverflow.com/questions/tagged/gethashcode)
The static implementation for Equals usually looks like this:
public static bool Equals(CreditProposal proposalA, CreditProposal proposalB)
{
// Check whether both values are null.
if(object.ReferenceEquals(proposalA, null)
&& object.ReferenceEquals(proposalB, null))
{
return true;
}
// Check whether either value is null.
if(object.ReferenceEquals(proposalA, null)
|| object.ReferenceEquals(proposalB, null))
{
return false;
}
// Check whether hashcodes are different.
if(proposalA.GetHashCode() != proposalB.GetHashCode())
{
return false;
}
// Check for value equality.
return Party.Equals(
proposalA.ContractingParty,
proposalB.ContractingParty)
&& ParentProposal.Equals(
proposalA.UltimateParent,
proposalB.UltimateParent);
// Add more conditions for equality here.
}
You would call this implementation from all your instance methods.

Related

If I implement IEquatable<T>, will I lose the option to compare by reference?

I would like to compare an object with antoher to know if they are equal or not. So it seems the way to do that is implementing the IEquatable interface in my class.
But I am not sure about how this affect to the behaviour of my class. Now, in my code, I use to compare two object by reference in this way:
if(myObject1 == myObject2)
{
// code when both objects are the same.
// Set values in some properties and do some actions according that.
}
else
{
// code when both objects are no the same.
// Set values in some properties and do some actions according that.
}
But in some special cases, mainly in testing, I would like to compare 2 objects and considerate equal if all the properties are equal, but in this case I don't know if it will affect to my main code, in which I am compare by reference.
Another option could be implement a method that compare in this way, but I don't know if it is a good idea or it is better to implement the IEquatable interface.
Thanks.
There are several different things going on here.
The first is that IEquatable<T> is not directly related to the == operator. If you implement IEquatable<T>, but you don't override the == operator, then == will continue to do what it currently does: compare your objects by reference.
IEquatable<T> gives you an Equals(T) method, and that's it. By itself, it doesn't affect Equals(object) (which you also need to implement), or == and !=.
So let's assume that you do overload the == operator, to call our Equals method:
public static bool operator ==(Foo left, Foo right) => Equals(left, right);
public static bool operator !=(Foo left, Foo right) => !Equals(left, right);
This has only changed the == operator between two Foo instances. You can still write:
if ((object)myObject1 == (object)myObject2))
and that will fall back to using object's == method, which compares by reference.
Another way to do this is:
if (ReferenceEquals(myObject1, myObject2))
which just does the same thing.
Also note that it's rare to implement IEquatable<T> for classes: there's really no point. Classes already have an Equals(object) method and a GetHashCode() method which you need to override, and adding an Equals(T) method doesn't give you much.
IEquatable<T> is however useful for structs: they also have an Equals(object) method you need to override, but if you actually call it then you're going to end up boxing, since it accepts object. If you implement IEquatable<T> here then you also get an Equals(T) method, which you can call without boxing anything.
All of that said, I would write your code as it's intended to work in your application, and do any testing-specific stuff in your test project. This means that if your objects should be compared by reference in your code, I wouldn't add anything new to the object itself.
In your test project, you can write your own method to check whether two instances of your object have the same properties (either as a custom bool AreFoosEqual(Foo f1, Foo f2), or as a full-blown IEqualityComparer<Foo> instance). You can then make this do exactly what your tests need, without worrying about breaking your application.
You can also write your test method as a series of assertions, which tells you which property is incorrect, and what the difference is. This can give you richer test output:
public static void AssertFoosEquals(Foo f1, Foo f2)
{
Assert.AreEqual(f1.Foo, f2.Foo, "Foo property mismatch");
Assert.AreEqual(f1.Bar, f2.Bar, "Bar property mismtach");
}
If you want to compare same objects but in different ways, I suggest using a comparer which implements IEqualityComparer<T>:
public class MyClassTestComparer : IEqualityComparer<MyClass> {
public bool Equals(MyClass x, MyClass y) {
if (ReferenceEquals(x, y))
return true;
else if (null == x || null == y)
return false;
return x.Propery1 == y.Property1 &&
x.Propery2 == y.Property2 &&
x.ProperyN == y.PropertyN;
}
public int GetHashCode(MyClass obj) {
return obj == null
? 0
: obj.Propery1.GetHashCode() ^ obj.Propery2.GetHashCode();
}
}
then you can choose the right comparer
public static IEqualityComparer<MyClass> MyClassComparer {
if (we_should_use_test_comparer)
return new MyClassTestComparer();
else
return EqualityComparer<MyClass>.Default;
}
Finally if will be
if (MyClassComparer.Equals(myObject1, myObject2)) {
// Equals: by reference or by properties (in test)
}
When you make a unit test ->
Like:
public void TestSomething()
{
var expectedValue1 = "SomeExpectedValue";
var actualValue = instance.Method();
Assert.Equal(expectedValue1, actualValue);
}
Then you "simply" assert the properties you want to look at, if you return an object and not a value:
public void TestSomething()
{
var expectedValue1 = "SomeExpectedValue";
TestableObject subject = instance.Method();
Assert.Equal(expectedValue1, subject.Somevalue);
}
If you want a more generic setup, you can write a reflection using generic flow, that looks at all properties on an object and attempts to match them to the another provided object.
Or you could download a nuget package of tools that already allow you to do this.
I would not override any functionality, simply for the purpose of testing. That way lies spaghetti code.
Ideally your code should be 100% verifiable by unit tests, without having specific code sections that augment or assist your testing methods. (Unless said code is restricted to the test project itself, and is not contained within any of the actual code being tested.

Why doesn't Contains call CompareTo nor Equals?

While comparing instances of a custom class, I noticed that a call to Contains doesn't work the way I expect it to. Assuming that the default comparison goes by the reference (pointer or whatever it's called), I implemented both CompareTo and Equals. I made sure to be implementing IComparable, of course.
It's still doesn't work and I get no hits when I put breakpoints on those methods.
What can I be missing and is the best option to use extension methods if I'm not?
public override bool Equals(Object input)
{
return Id == ((MyType) input).Id;
}
public int CompareTo(Object input)
{
return Id - ((MyType)input).Id;
}
A better implementation could be:
public bool Equals(MyType other)
{
// if 'other' is a null reference, or if 'other' is more derived or less derived
if ((object)other == (object)null || other.GetType() != GetType())
return false;
// OK, check members (assuming 'Id' has a type that makes '==' a wise choice)
return Id == other.Id;
}
public override bool Equals(object obj)
{
// call to other overload
return Equals(obj as MyType);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
You can mark the class as implementing IEquatable<MyType> in that case (but it will work even without that).
Regarding GetHashCode: Always remember to override it. You should have seen a compiler warning that it was problematic to override Equals(object) without overriding GetHashCode. Never keep the code return base.GetHashCode() in the override (assuming the base class is System.Object). Either give it a try and implement something based on the members that participate in Equals. If you do not think GetHashCode will actually be used in your case, say:
public override int GetHashCode()
{
throw new NotSupportedException("We don't have GetHashCode, sorry");
}
If you absolutely know that you will only be using List<>.Contains, and not e.g. Dictionary<,>, HashSet<> and not Linq's Distinct(), etc. etc., it could work with GetHashCode() simply throwing.
IComparable<MyType> is not needed unless you sort List<MyType> or MyType[], or you use Linq's OrderBy with MyType, or you use SortedDictionary<,>, SortedSet<>.
Overloading operator == is not needed for these uses.

Overloaded operator arguments always null

So I have a class which overrides Equals(object obj) and GetHashCode() along with implementing IEquatable. To make working with this type a little more natural when checking for equality I thought, heck, I'd overload the equality operator and inequality operator, no worries...
Uh oh, worries... consider the following - where both myType instances are NOT null:
if (myType != container.myType) //NullReferenceException
{
//never get here
}
//never get here either
Now, container is just another class to hold an instance of myType among other things which is used for caching items.
Here's the actual (relevant) code from myType:
public class MyType : IEquatable<MyType>
{
public static bool operator ==(MyType myTypeA, MyType myTypeB)
{
return myTypeA.Equals(myTypeB);
}
public static bool operator !=(MyType myTypeA, MyType myTypeB)
{
return !(myTypeA == myTypeB);
}
public override bool Equals(object obj)
{
if (obj != null && obj is MyType)
{
return Equals((MyType)obj);
}
return false;
}
public bool Equals(MyType other)
{
if (other != null)
{
return other.ToString() == ToString();
}
return false;
}
}
Any experience on this front?
Thanks.
Couple of pointers -
If you've overridden == and != on classes, make sure to use ReferenceEquals to check for null inside the overload implementations rather than ==, as that will call your overloaded operator and either go into a loop or try to call Equals on a null this reference, which is probably what is happening here.
Don't override == and != on classes. Those operators are meant for value equality, and classes aren't really designed to have value equality. Either remove the operator overloads, or make MyType a struct.
Tricky one... the problem is that you use the equality operator inside the Equal override as follows:
public bool Equals(MyType other)
{
if (other != null)
It goes to your overloaded != operator, which in turn goes to your == operator, which trying to do null.Equals...
As the others have stated you need to be carefull checking for nulls as it will call your equality function again, normally resulting in a StackOverflowException.
When I use the IEquatable interface on classes I normally use the following code:
public override bool Equals(object obj)
{
// If obj isn't MyType then 'as' will pass in null
return this.Equals(obj as MyType);
}
public bool Equals(MyType other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
// Actual comparison code here
return other.ToString() == this.ToString();
}

Is it ever acceptable to return True when the parameter to Equals is a null reference?

The docs for Object.Equals says that implementors must return false if the parameter is a null reference.
In my class, I'm overriding Equals to check for value equality. I have a member variable which is similar to the Nullable (T) structure. My initial inclination is to return True when I'm passed a null reference and my structure's HasValue property is False.
Is it ever acceptable to return True when the parameter to Equals is a null reference?
EDIT
For illustration:
class ExampleClass {
SomeValueType? x;
bool Equals(object other) {
if (other == null) return false; // <-- returns a different value than x.Equals
return x.Equals(other);
}
}
Nullable<T>.Equals(object) is the following:
public override bool Equals(object other)
{
if (!this.HasValue)
{
return (other == null);
}
if (other == null)
{
return false;
}
return this.value.Equals(other);
}
So the answer to your question is yes in the case of a struct (value type) with nullable semantics. If your type is a class (reference type), the answer is definitely no.
Actually it is not. The equals method cannot return true when two objects are null.
Why?
Well when you define
AnObject obj;
obj is a reference to an object (I am talking for Java but this must be a OO concept)
Object.Equals method takes a parameter which must be an object however null is not an object.
so null.Equals(null) is not an acceptable approach for OO.
Edit:
That's why == operator differs from obj.Equals method. null == null returns true without any headache.
Edit2: It seems that .Net has an inconsistency about Equals method which may be subject to another topic.
int? a = null;
a.Equals(null); // returns true without any problem.
but:
Nullable<T>.Equals method is defined like this:
Nullable<T>.Equals(object obj):bool
Indicates whether the current
Nullable value is equal to a
specified object
Since null is not an object, either the documentation or the implementation is not correct.

C# - List<T>.Remove() always deletes the first object on the list

Working in Visual Studio 2008 (C#)...
I use a List collection to store instances of my custom class (Shift).
I want to delete a certain shift from the list by using the Remove method.
But List.Remove() always deletes the first item it finds.
I've implemented the IComparable interface for my Shift, I thought this would be enough, then I added an implementation of IEqualityComparer, and it still has no effect.
Here's the excerpt with my implementation:
region IComparable Members
public int CompareTo(object obj)
{
Shift s1 = this;
Shift s2 = (Shift)obj;
if (s1.start.time != s2.start.time)
return s1.start.CompareTo(s2.start);
else
return s1.end.CompareTo(s2.end);
}
endregion
region IEqualityComparer Members
public bool Equals(Shift x, Shift y)
{
if ((x.opening) != (y.opening)) return false;
if ((x.closing) != (y.closing)) return false;
if (!x.opening) if (x._start != y._start) return false;
if (!x.closing) if (x._end != y._end) return false;
if (x.when != y.when) return false;
if (x.day != y.day) return false;
if (x.EmployeeID != y.EmployeeID) return false;
return true;
}
public int GetHashCode(Shift obj)
{
return obj.ToString().ToLower().GetHashCode();
}
endregion
And yet, still - when the List contains two shifts, say "8:00 - 15:00"; "12:00 - 16:00", calling Remove("12:00-16:00") results in "8:00 - 15:00" getting removed, and the latter one remains in the collection!
What's wrong here? Thx
You can override object.GetHashCode and object.Equals:
public override bool Equals(object obj)
{
if(obj == null)
{
return false;
}
return Equals(this, obj as Shift);
}
public override int GetHashCode()
{
return this.GetHashCode(this);
}
You should also probably do a null check in Equals(x, y).
IComparable is not normally used to compare for equality (it's used for ordering), so List<T>.Remove() ignores it.
IEqualityComparer is not an equivalent of IComparable for equality purposes. It is supposed to be implemented by a comparer object - that is, an object that compares other objects for equality. If you want equality comparisons to be inherent to your class, then you rather need to implement IEquatable<T>. Or just override Object.Equals() and Object.GetHashCode() on your class, without implementing any interfaces.
Remove uses EqualityComparer<T>.Default to determine equality and choose which object to remove, which will use IEquatable<T> if it's implemented on your object, otherwise, it will use reference equality.
You have two options to get the behavior you want:
1) Make Shift implement IEquatable<T> (not just override Object.Equals or make the method, but make Shift - Shift : IEquatable<Shift>)
2) Use List<T>.RemoveAt
With the example you provided, you're calling:
List<Shift>.Remove("12:00 - 16:00");
"12:00 - 16:00" in this case, is a String value and not an actual Shift object. Make sure that in your CompareTo method that you're code is properly casting the String value to a Shift object. Otherwise, when it compares start times...things could go haywire.

Categories

Resources