Why code inside Generic functions ignores overloaded == operator - c#

What is the workaround to this problem?
class Program
{
static void Main(string[] args)
{
var a = new Test();
var b = new Test();
var eq = Check(a, b);
}
private static bool Check<T>(T a, T b) where T : class
{
return a == b; //will not call overloaded ==
}
}
public class Test
{
public override bool Equals(object obj)
{
Test other = obj as Test;
if (ReferenceEquals(other, null)) return false;
return true;
}
public static bool operator ==(Test left, Test right)
{
return Equals(left, right);
}
public static bool operator !=(Test left, Test right)
{
return !(left == right);
}
}

The == operator is not used because your generic method exists independently of the types you will use for T. It has no way of knowing that all types used as T will overload the == operator... You can use the Equals method instead:
private static bool Check<T>(T a, T b) where T : class
{
return Equals(a, b);
}

The 'solution' here is to call
private static bool Check<T>(T a, T b) where T : class
{
//return a == b; // will not call overloaded ==
return a.Equals(b); // will cal overloaded Equals
}

It's a known behavior. MSDN says:
When applying the where T : class constraint, it is recommended that
you do not use the == and != operators on the type parameter because
these operators will test for reference identity only, not for value equality. This is the case even if these operators are overloaded in
a type used as an argument.
To check equality you have to implement IEqualityComparer (or directly call one of the Equal methods).

The workaround is to call the virtual Equals method, and override that:
private static bool Check<T>(T a, T b) where T : class
{
return a.Equals(b);
}
The overloaded == operator is resolved at compile time, so it is resolved to the System.Object implementation of the operator. A virtual method call is dispatched at run time, so the override of System.Object.Equals (if any) will get called.
In your code, the virtual Equals call is occurring in the overloaded == method, which is not called; that's why the Equals override is not called.
Another solution, if you have control of the classes being passed to the method, would be to constrain to IEquatable<T>, and implement that in your classes:
private static bool Check<T>(T a, T b) where T : class, IEquatable<T>
{
return a.Equals(b);
}
That will cause the overload to resolve to the Equals(T) method, which will save some type checking at run time.

Related

C# operator overload members mirroring

Today I've encountered a problem with operators overloading. I have a class
public sealed class StringIdentifier : IIdentifier
{
private readonly string _identifier;
public StringIdentifier(string identifier)
{
_identifier = identifier;
}
public object GetIdentifier()
{
return _identifier
}
public static implicit operator StringIdentifier(string value) => new StringIdentifier(value);
public static implicit operator string(StringIdentifier value) => value._identifier;
public static bool operator ==(StringIdentifier a, string b) => a?._identifier == b;
public static bool operator !=(StringIdentifier a, string b) => a?._identifier != b;
}
The problem is, that checking if (StringIdentifier == string) uses the written bool operator, however, using if (string == StringIdentifier) does 2 implicit conversions (thus creates single garbage object (StringIdentifier)) to meet the format operator ==(StringIdentifier a, string b).
I know this can be solved by writing the same operator overload just switching the members (i.e. public static bool operator ==(string a, StringIdentifier b), however, that just creates more methods (and pretty much duplicates the code) but logically nothing is changed.
My question is, is there a way to do automatic operator members mirroring (StringIdentifier == string would be mirrored as string == StringIdentifier), so that I would not need to write same comparison overload twice (or call switched members comparison in overload)?

What's the relation between GetHashCode and Equals in a IEqualityComparer implementation? [duplicate]

This question already has answers here:
Why is it important to override GetHashCode when Equals method is overridden?
(15 answers)
IEqualityComparer GetHashCode being called but Equals not
(4 answers)
Closed 8 years ago.
I have a class A that inherits from a class B and implements IEqualityComparer<A>.
This means class A provides its own implementation of both Equals and GetHashCode methods. So far so good.
The problem is that I don't understand why the code behaves in the following way:
debugger will only reach A's Equals implementation breakpoint if A's GetHashCode implementation returns
this.GetHashCode() instead of
obj.GetHashCode(), with "obj" being the parameter that GetHashCode's signature defines(a variable of type A, in my case).
Intuitively, I thought that I should return the hashcode of the object I received, but doing so makes the compiler ignore the instance's Equals implementation.
Why does this happen?
Code demonstration:
public class A : B, IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
//my implementation...
}
public int GetHashCode(A obj)
{
//return obj.GetHashCode(); -> this makes my Equals implementation above be ignored! Why?
return this.GetHashCode(); -> my Equals implementation is used
}
}
It sounds like you are using the wrong interface. IEqualityComparer<> is typically used for a class that compares instances of other types.
Your type should simply implement IEquatable<A> and override Equals(object) and GetHashCode(). Note the signatures.
Like this:
public class A : B, IEquatable<A>
{
public bool Equals(A other)
{
if (other == null || GetType() != other.GetType())
return false;
//your implementation
}
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public override int GetHashCode()
{
//your implementation
}
}
Then you can do stuff like someEnumerableOfA.Distinct() and the Linq method will use your implementation.
The other option is to do:
public class A : B // no interfaces
{
}
public class AEqualComparer : IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
//your implementation
}
public int GetHashCode(A x)
{
//your implementation
}
}
With this other option you need someEnumerableOfA.Distinct(new AEqualComparer ()).
Implementing IEqualityComparer<T> doesn't override the base implementation of GetHashCode and Equals.
Implementing IEqualityComparer<T> allows you to supply an instance of the implementor as an equality comparer for T. This is a common parameter to several linq extensions and generic collection constructors.
Overriding Equals and GetHashCode effects the way instances of a class are tested for equality. Tapping into other implmentations that call Equals and GetHashCode, like the base = and != operators and linq extensions and generic collection constructors where you don't supply an alternative IEqualityComparer<T>.
These concepts are similar but serve different purposes, they are not partially interchangable.
Let me expand with an example,
public class A
{
public string Value1 { get; set; }
public int Value2 { get; set; }
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = (hash * 23) +
StringComparer.Ordinal.GetHashCode(this.Value1);
hash = (hash * 23) + this.Value2;
return hash;
}
}
public override bool Equals(object obj)
{
var a = obj as A;
if (a == null)
{
return false;
}
if (a.Value2 != this.Value2)
{
return false;
}
return StringComparer.Ordinal.Equals(
a.Value1,
this.Value1);
}
}
This implementation of A correctly overrides Equals and GetHashCode, this change is sufficient to ensure that after calling the linq extension
var distinct = aSequneceOfA.Distinct();
distinct will not contain any instances that have both the same Value2 and ordinally comparable Value1. No other interface implementation is necessary to achieve this.
Now, suppose that in some situation I wasn't happy with this ordinal comparison for Value1, perhaps I require some case insensitivity. I might implement an new equality comparer.
public class AComparerInsensitive : IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
if (x == null)
{
return y == null;
}
if (y == null)
{
return false;
}
if (x.Value2 != y.Value2)
{
return false;
}
return StringComparer.CurrentCultureIgnoreCase.Equals(
x.Value1,
y.Value1)
}
public int GetHashCode(A a)
{
if (a == null)
{
return 0;
}
unchecked
{
int hash = 17;
hash = (hash * 23) +
StringComparer.CurrentCultureIgnoreCase.GetHashCode(
a.Value1);
hash = (hash * 23) + a.Value2;
return hash;
}
}
}
This would allow me to call the alternative overload of Distinct,
var insensitivelyDistinct = aSequneceOfA.Distinct(
new AComparerInsensitive());
This overload of distinct ingnores As overridden Equals and GetHashCode and uses AComparerInsensitive to perform the comparison.

C# generics class operators not working

I have a problem with generic. When I try to use less operators in generic, their call is not happening. But it works with the method Equals.
That is a some test class:
public class Test
{
public int i;
static public Boolean operator ==(Test obj1, Test obj2)
{
Console.WriteLine("operator ==");
return obj1.i == obj2.i;
}
static public Boolean operator !=(Test obj1, Test obj2)
{
Console.WriteLine("operator !=");
return obj1.i != obj2.i;
}
public override bool Equals(object obj)
{
Console.WriteLine("operator equals");
return this == (Test)obj;
}
public override int GetHashCode()
{
Console.WriteLine("HashCode");
return 5;
}
}
And class Checker:
public class Checker
{
public Boolean TestGeneric<T>(T Left, T Right) where T : class
{
return Left == Right; //not work override operators
return Left.Equals(Right); //work fine
}
}
Small testing:
Test left = new Test() { i = 4 };
Test right = new Test() { i = 4 };
var checker = new Checker();
Console.WriteLine(checker.TestGeneric<Test>(left, right));
Console.ReadKey();
How I can use less operators in class Test from generic?
Overloaded operators are static methods, so they don't participate in polymorphism; they are resolved statically at compile time, based on the known type of the operands.
In a generic method, the compiler can't know that T will be Test (since it could actually be anything else), so it uses the most general definition of ==, which is reference comparison.
Note that if you add a constraint on the generic method to force T to be Test or a subclass of Test, it will work as expected, but of course it won't work anymore for other types...
This now works in C# 11 / .NET 7 (or above):
public class Test : IEqualityOperators<Test, Test, bool>
{ /* no changes except ^^^ addition */ }
public bool TestGeneric<T>(T Left, T Right) where T : IEqualityOperators<T, T, bool>
{
return Left == Right; // does what you expect
}

How to step into an interface method (Equals)

I've implemented the iEquatable interface:
LineItem : IEquatable<LineItem>
But now I want to debug my Equals(...) method by stepping through the code. But even in debug mode, stepping in doesn't go into it (i.e. F11), and putting a breakpoint inside the method doesn't get me into it either. How can I debug it??
Not that it should be relevant but here is my Equals method:
public bool Equals(LineItem other)
{
List<bool> individuals = new List<bool>();
individuals.Add(DateTime.Equals(Expiry, other.Expiry));
individuals.Add(Code == other.Code);
individuals.Add(Type == other.Type);
individuals.Add(Class == other.Class);
Func<object, object, bool> Compare = delegate(object A, object B)
{
if (A == DBNull.Value || B == DBNull.Value)
return A == B;
else
return (double)A == (double)B;
};
individuals.Add(Compare(Strike, other.Strike));
individuals.Add(Compare(Future, other.Future));
individuals.Add(Compare(Premium, other.Premium));
individuals.Add(Compare(Volatility, other.Volatility));
individuals.Add(Compare(Volume, other.Volume));
individuals.Add(Compare(OpenInterest, other.OpenInterest));
individuals.Add(Compare(Delta, other.Delta));
return !individuals.Contains(false);
}
EDIT:
I'm calling the method from elsewhere in my code like this now:
if(!fo.Future.Equals(li))...
but that still doesn't let me debug it.
You need to take a big step back and learn how to implement equality methods correctly in the first place. C# was designed to be a "pit of success" language; that is, you should naturally "fall into" doing things the right way. Unfortunately, equality is not a "pit of success" in C#; the language designers failed to make it easy to do it right the first time.
Here's the pattern that I use when I override equality.
First, start by writing a private static method that does everything right. Everything else will use this method. Start your method by dealing with (1) the reference equality early out, and (2) null checks.
private static MyEquality(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
// We now know that they are not BOTH null. If one is null
// and the other isn't then they are not equal.
if (ReferenceEquals(x, null)) return false;
if (ReferenceEquals(y, null)) return false;
// Now we know that they are both non-null and not reference equal.
... check for value equality here ...
}
OK, now that we have that, we can use that to implement everything else.
public override bool Equals(object y)
{
return MyEquality(this, y as Foo);
}
public override int GetHashcode()
{
// Implement GetHashcode to follow the Prime Directive Of GetHashcode:
// Thou shalt implement GetHashcode such that if x.Equals(y) is true then
// x.GetHashcode() == y.GetHashcode() is always also true.
}
public bool Equals(Foo y)
{
return MyEquality(this, y);
}
That is what is necessary to correctly implement IEquatable<T>.Equals. You should also consider overriding the == operator to be consistent:
public static bool operator ==(Foo x, Foo y)
{
return MyEquality(x, y);
}
public static bool operator !=(Foo x, Foo y)
{
return !MyEquality(x, y);
}
Now no matter whether you call object.Equals(foo, bar), foo.Equals(bar), or foo == bar, you have consistent behavior.
LineItem.Equals(a, b) is a static method call to Object.Equals(object, object); it isn't your method.
This implementation will call a.Equals(object) if you've overridden it, but you did not override it.

Why is this not working? (Generic Equals Helper)

SOLVED!
This works, I need to tell the compiler that T implements IEquatable of course...
public static bool secureEquals<T>(T obj1, object obj2)
where T: class, IEquatable<T>
{...
public static bool secureEquals<T>(T obj1, T obj2)
where T: class, IEquatable<T>
{....
Question:
I tried to put repeated functionality of IEquatable implementations and Equals overrides into a separate static class like so:
public static class EqualsHelper
{
public static bool secureEquals<T>(T obj1, object obj2)
where T : class
{
if (obj2 is T)
{
return secureEquals(obj1, obj2 as T);
}
else
{
return false;
}
}
public static bool secureEquals<T>(T obj1, T obj2)
{
if (obj1 == null)
{
if (obj2 != null)
return false;
}
else
{
if (!obj1.Equals(obj2)) //this calls Dummy.Equals(object other)!
return false;
}
return true;
}
public static bool secureEquals(double[] obj1, double[] obj2)
{
if (obj1.Length != obj2.Length)
return false;
for (int i = 0; i < obj1.Length; ++i)
{
if (obj1[i] != obj2[i])//ok for doubles if they are generated in the same way? I guess so!
return false;
}
return true;
}
public class Dummy : IEquatable<Dummy>
{
public Dummy(string member)
{
_member = member;
}
private string _member;
public virtual bool Equals(Dummy other)
{
return this._member == other._member;
}
public override bool Equals(object other)
{
return EqualsHelper.secureEquals(this, other);
}
}
static void Main(string[] args)
{
Dummy d1 = new Dummy("Hugo");
Dummy d2 = new Dummy("Hugo");
object d2obj = (object)d2;
bool ret = d1.Equals(d2obj);
}
The idea was:
d1.Equals(d2obj) calls Dummy.Equals(object) calls EqualsHelper.secureEquals(T, obj) calls EqualsHelper.secureEquals(T, T) calls Dummy.Equals(Dummy).
The last call however calls Dummy.Equals(object), even though everything is typed to T there.
What am I missing?
PS: I know that replacing the call with:
if (!((IEquatable<T>)obj1).Equals(obj2)) //this calls Dummy.Equals(object other)!
does the trick, but why is it not working otherwise?
Why: because method invoke here is static typed, and the only available Equals involving a T with no generic constraint is object.Equals(object). The exact same IL has to be able to handle every T - C# generics are not like C++ templates; no per-T overload resolution occurs.
As an aside: you might also want to look at EqualityComparer<T>.Default.Equals(obj1,obj2), which will handle IEquatable<T>, Nullable<T>, etc automatically:
public static bool secureEquals<T>(T obj1, object obj2) where T : class
{
return EqualityComparer<T>.Default.Equals(obj1, obj2 as T);
}
The Equals overload within EqualsHelper.secureEquals is resolved when EqualsHelper is compiled - and that code doesn't know whether T implements IComparable<T> or not, so all that's left is Equals(Object). You can add a constraint to T which would make it use the right overload:
public static bool SecureEquals<T>(T obj1, T obj2) where T : IEquatable<T>
Of course, this would limit the classes with which you could use it.
(As an aside, note that I've renamed secureEquals to SecureEquals to comply with .NET naming conventions. I'd also not use the word "secure" here at all personally - there's nothing security-sensitive here.)
Because in your secureEquals you have no constraints, and compiler always assumes Object.Equals exist. Add interface constraint for your T.

Categories

Resources