operator== in base and Equals in derived - c#

I have a base class that is compared by reference, and a derived class that is compared by value (showing just the lines that are relevant here):
class Term : IReadOnlyList<Term>
public static bool operator ==(Term a, Term b)
{
if (ReferenceEquals(a, null))
return false;
return a.Equals(b);
}
sealed class CompoundTerm : Term, IReadOnlyList<Term>
public override bool Equals(object o)
So the derived class overrides Equals, but the base class has to overload == because it is possible and indeed likely that a == b will occur in a context where a and b are declared as Term but actually point to CompoundTerm.
As far as I can tell - please correct me if I'm wrong - this is all necessary and correct.
The compiler unfortunately is not happy with it:
Term.cs(40,11): warning CS0660: 'Term' defines operator == or operator != but does not override Object.Equals(object o)
What's the best thing to do here? I could use the brute force solution of disabling the warning, but I'd like to check and make sure there isn't a more elegant solution, some idiom I'm missing.

I have a base class that is compared by reference, and a derived class
that is compared by value (showing just the lines that are relevant
here)
Your current implementation doesn't necessarily perform reference equality; it actaully calls potential overloads of Equals.
So the derived class overrides Equals, but the base class has to overload == ...
I don't understand why, if the base class overrides Equals, you need to overload == in the base class. == already performs reference comparison if no overload is defined, because the static == (object, object) is resolved at compile time.
... it is possible and indeed likely that a == b will occur in a context where a and b are declared as Term but actually point to CompoundTerm.
What the real type of a and b are is irrelevant when calling the == operator. == is a static method and will therefore resolve based on the reference type of the arguments:
object aString = "Hello";
object theSameString = new string(new[] { 'H', 'e', 'l', 'l', 'o' }); //to avoid string interning
var referenceEquals = aString == theSameString; //false: object == object
var valueEquals = (string)aString == (string)theSameString; //true: string == string
Now what I understand you are trying is precisely to perform reference equality when calling == if a and b are Term and not a subclass and to otherwise perform potential value equality.
This seems rather confusing, to be honest. I'd recommend having == always perform reference equality (don't overload it) and if you need potential value equality use Equalsand document the class or code to make this behavior clear.

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.

Comparing structs in a generic method

Here's a simplified case of what I'm struggling with:
public bool CompareStruct<S>(S a, S b) where S : struct
{
return a == b;
}
The above will not compile with the error Operator '==' cannot be applied to operands of type 'S' and 'S'.
Normally, I wouldn't be surprised. But I've indicated that S is a struct - so why can't I compare the two parameters?
I don't think this SO question has any relevancy here - after all, I'm working with struct types, not reference types.
The problem here is that the default behavior of == in C# is reference equality. Reference equality in structs makes no sense because it will always return false.
The compiler has no way of knowing if == has been overloaded and S has value equality semantics and therefore disallows its use.
To get around this, use Equals and consider constraining S to IEquatable<S> if appropiate to avoid unnecessary boxing operations.
The problem is that when you specify the constraint that the generic type parameter is struct i.e. ValueType, it is not necessary that the struct which calls this method has provided the overload implementation for == and != operator for it, as for custom value types, when we define it we need to provide the == and != operator overloads for them to be used.
An alternate can be to use Object.Equals method or call the Equals() method on it's own instance like:
public bool CompareStruct<S>(S a, S b) where S : struct
{
return a.Equals(b);
}
or:
public bool CompareStruct<S>(S a, S b) where S : struct
{
return Object.Equals(a,b);
}
The point to remember is that but the equality operator is by default not available for value types unless you overload the == operator for that type and for reference types using == operator does is checking for reference equality so that's why applying constraint to class works fine.
I once wrote a post about this which might be helpful which can be read at this link (Equality Operator (==) and Value Types in C#)
You can't use == on user-defined ValueTypes unless you explicitly override the == and != operators. This is because the default implementation for a struct doesn't implement these operators. For instance, the below doesn't compile:
struct Foo
{
}
void Main()
{
Foo f1;
Foo f2;
if(f1 == f2) // The compiler complains here
{
}
}
So if you can't do that for known structs (by default), then you can't do that for generic structs (less information known at compile time) unless you provide more information (for example that this struct have to implement IEquatable<S>)
The above would work for classes because they uses reference equality by default when using ==. That doesn't apply to Value Types because they are copied by value.

Performance of == vs Equals in generic C# class

For some reason C# does not allow == operator use in generic classes like here:
class Mine<T> where T : struct
{
T val;
public T Value
{
set
{
if (val == value) // Operator '==' cannot be applied to operands of type T and T happens here
{
// .. do something ...
}
}
}
}
If I replace == with val.Equals(value) I have code that works as expected but if I look at bytecode it looks much more complicated.
A very simple test comparing int variables in the loop using == and Equals() showed that Equals() version was two times slower than "==" version.
I wonder if there is a way to compare primitive value types in generic classes that would be as fast as == operator.
Any ideas welcome.
Edit:
I got lost between timers. Performance difference is not as dramatic. Here are my latest results:
== operator 1974380 ticks
Equals() 1976358 ticks
== operator in another static function 1974604 ticks
EqualityComparer<int>.Default... 32486695 ticks
In short: Equals() is good enough.
The reason being that == defaults to reference equality and that makes no sense for value types, the answer will always be false. Because there is no language mechanism to constrain generic types based upon static methods, the compiler simply disallows this as it can't verify that T really has an overloaded == operator.
On the other hand if you constraint T to class it will compile just fine because reference equality does make sense for reference types.
The solution is of course IEquatable<T>; in any sanely implemented struct IEquatable<T>.Equals(T t) will give you value equality semantics and == should behave consistently.
And answering your question, no there is not. If you really need the speed of int == int you will need to implement a non generic specialized class.
If you are allowed to add the IEquatable<T> constraint to the class, then you can use the IEquatable<T>.Equals(T other) method declared in that interface:
class Mine<T> where T : struct, IEquatable<T>
{
T val;
public T Value
{
set
{
if (val.Equals(value)) //
{
// .. do something ...
}
}
}
}

C# operator overloading == and pragma warnings 660 & 661 not overriding Equals and GetHashCode when irrelevant

Why does the C# compiler complain with pragma warning 660 & 661
"FooClass" defines operator == or operator != but does not override Object.Equals(object o)
"FooClass" defines operator == or operator != but does not override Object.GetHashCode()
When adding additional operators, such as:
public static bool operator ==(FooClass foo, string fooId)
I am not specifying
public static bool operator ==(FooClass foo, FooClass foo2)
Which this would make sense to override Object.Equals and GetHashCode.
Is this just a limitation in the compiler that it's not properly checking the arguments specified in the operator?
The general guideline is doing foo == bar should return the same result as foo.Equals(bar), that is the reason for the warning. It is a guideline, not a requirement, and that is why it is a warning instead of a error.
The 2nd warning is because of the rule that if(foo.Equals(bar)) foo.GetHashCode() == bar.GetHashCode(). If two objects are equal, their hash codes should also be equal. Many things in the .NET framework and 3rd party libraries rely on this so if you don't do it things like Dictionary that use GetHashCode() for lookups is going to break.
So if I can do
FooClass foo = new FooClass("Foo");
if(foo == "Foo")
{
//...
}
I expect to be able to do
FooClass foo = new FooClass("Foo");
Hashtable hash = new Hashtable();
hash.Add(foo, "Bar");
var result = hash["Foo"];

5 ways for equality check in .net .. why? and which to use?

While learning .net (by c#) i found 5 ways for checking equality between objects.
The ReferenceEquals() method.
The virtual Equals() method. (System.Object)
The static Equals() method.
The Equals method from IEquatable interface.
The comparison operator == .
My question is :
Why there are so many Equals() method along with comparison operator?
Which one of the virtual Equals() or IEquatable's Equals() sholud be used .. (say if we use our own collection classes)
1 - Reference equals checks if two reference type variables(classes, not structs) are referred to the same memory adress.
2 - The virtual Equals() method checks if two objects are equivalent. Let us say that you have this class:
class TestClass{
public int Property1{get;set}
public int Property2{get;set}
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TestClass))
return false;
var convertedObj = (TestClass)obj;
return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
}
}
and you instantiate 2 objects from that class:
var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}
although the two objects are not the same instance of TestClass, the call to o1.Equals(o2) will return true.
3 - The static Equals method is used to handle problems when there is a null value in the check.
Imagine this, for instance:
TestClass o1 = null;
var o2 = new TestClass{property1 = 1, property2 = 2}
If you try this:
o1.Equals(o2);
you wil get a NullReferenceException, because o1 points to nothing.
To adress this issue, you do this:
Object.Equals(o1,o2);
This method is prepared to handle null references.
4 - The IEquatable interface is provided by .Net so you don't need to do casts inside your Equals method.
If the compiler finds out that you have implemented the interface in a class for the type you are trying to check for equality, it will give that method priority over the Object.Equals(Object) override.
For instance:
class TestClass : IEquatable<TestClass>
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TestClass))
return false;
var convertedObj = (TestClass)obj;
return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
}
#region IEquatable<TestClass> Members
public bool Equals(TestClass other)
{
return (other.Property1 == this.Property1 && other.Property2 == this.Property2);
}
#endregion
}
now if we do this:
var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}
o1.Equals(o2);
The called method is Equals(TestClass), prior to Equals(Object).
5 - The == operator usually means the same as ReferenceEquals, it checks if two variables point to the same memory adress.
The gotcha is that this operator can be overrided to perform other types of checks.
In strings, for instance, it checks if two different instances are equivalent.
This is a usefull link to understand equalities in .Net better:
CodeProject
The ReferenceEquals() method.
This is used to test if two given variables point (the symbol references) to the same object. It is literally equivalent to ((object)a) == ((object)b). If you override the comparison operator (==) then ReferenceEquals maintains a way to access the default behaviour.
However, if you are dealing with a value type (e.g. a struct) then this will always return false. This is because the comparison boxes each value type to a new object so naturally the references will not be equal.
The virtual Equals() method. (System.Object)
This is the default way to semantically compare two objects (of any type). Each class overrides this as they choose. By default it is equivalent to a CLR call (InternalEquals) that basically compares memory references.
Note, if two objects return true for Equals() then GetHashCode() on each of them must be equal. However, if the hash codes for two objects are value equivalent (i.e. obj1.GetHashCode() == obj2.GetHashCode()) this does not means that Equals() is true.
Your class should typically implement Equals and GetHashCode as a means to distinguish class instances, and must implement this or the == operator (ideally both) if it is a value type.
Note, for value types the default Equals behaviour is that of ValueType.Equals() which if you look in Reflector (or read the MSDN description) uses reflection to compare the members of the two value instances.
The static Equals() method.
This is equivalent to return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))) where each type is converted to Object for testing. My testing shows that overloaded comparison operators are ignored, but your Equals method will be used if the objects are not null and aren't the same reference. As such, a.Equals(b) does not necessarily equal object.Equals(a, b) (for the cases where ((object)a) == ((object)b) or either a or b is null).
The Equals method from IEquatable interface.
IEquatable provides a way for you to treat comparison to instances of the same class specially. Having said that your Equals method should be handling the behaviour the same way:
If you implement Equals, 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.Equals
method
Nevertheless you should implement IEquatable:
To handle the possibility that objects
of a class will be stored in an array
or a generic collection object, it is
a good idea to implement IEquatable
so that the object can be easily
identified and manipulated.
The comparison operator ==
The comparison operator by default returns true when both of your objects are the same reference.
It is not recommended to override the comparison operator unless you are dealing with a value type (in which case it is recommended, along with the Equals method) or an immutable reference type which you would usually compare by value (e.g. string). Always implement != at the same time (in fact I get a requires a matching operator '!=' to also be defined error if I do not).
Resources:
Link
Where is the implementation of InternalEquals(object objA, object objB)
http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx
http://msdn.microsoft.com/en-us/library/2dts52z7.aspx
http://msdn.microsoft.com/en-us/library/ms131190.aspx
http://msdn.microsoft.com/en-us/library/ms173147(VS.80).aspx
http://msdn.microsoft.com/en-us/library/ms182276(VS.80).aspx
Each version of equality is slightly different.
ReferenceEquals tests for reference equality.
virtual Equals by default checks for reference equality for class types and value equality for struct types. It can be overridden to define equality differently, if desired; and should be overridden for value types.
static Equals just calls virtual Equals, but also allows for null arguments.
IEquatable<T>.Equals is a generic/type-safe equivalent for virtual Equals.
operator== is intended to be like the default virtual Equals, meaning reference equality for class types (unless the class also overrides other operators). It should also be overridden for value types.
If you write your own collection class, use IEqualityComparer<T>, defaulting to EqualityComparer<T>.Default. Don't use any of the equality comparisons directly.
For primitives, stick with the == operator.
In most objects supplied in the .NET framework and any custom objects you create the .Equals() method and the == operator will only check to see if two objects refer to the same object on the heap.
The purpose of the IEquatable interface is to override the .Equals() method to change its behavior from checking for referential equality to check for value equality. The System.String type is an example of a built-in .NET object which implements this interface.
The .ReferenceEquals() method provides a way for developers who've overriden the standard .Equals() method to still be able to check two objects for referential equality.

Categories

Resources