Generic Equality Comparer [duplicate] - c#

According to the documentation of the == operator in MSDN,
For predefined value types, the
equality operator (==) returns true if
the values of its operands are equal,
false otherwise. For reference types
other than string, == returns true if
its two operands refer to the same
object. For the string type, ==
compares the values of the strings.
User-defined value types can overload
the == operator (see operator). So can
user-defined reference types, although
by default == behaves as described
above for both predefined and
user-defined reference types.
So why does this code snippet fail to compile?
bool Compare<T>(T x, T y) { return x == y; }
I get the error Operator '==' cannot be applied to operands of type 'T' and 'T'. I wonder why, since as far as I understand the == operator is predefined for all types?
Edit: Thanks, everybody. I didn't notice at first that the statement was about reference types only. I also thought that bit-by-bit comparison is provided for all value types, which I now know is not correct.
But, in case I'm using a reference type, would the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?
Edit 2: Through trial and error, we learned that the == operator will use the predefined reference comparison when using an unrestricted generic type. Actually, the compiler will use the best method it can find for the restricted type argument, but will look no further. For example, the code below will always print true, even when Test.test<B>(new B(), new B()) is called:
class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test<T>(T a, T b) where T : A { Console.WriteLine(a == b); } }

As others have said, it will only work when T is constrained to be a reference type. Without any constraints, you can compare with null, but only null - and that comparison will always be false for non-nullable value types.
Instead of calling Equals, it's better to use an IComparer<T> - and if you have no more information, EqualityComparer<T>.Default is a good choice:
public bool Compare<T>(T x, T y)
{
return EqualityComparer<T>.Default.Equals(x, y);
}
Aside from anything else, this avoids boxing/casting.

"...by default == behaves as described above for both predefined and user-defined reference types."
Type T is not necessarily a reference type, so the compiler can't make that assumption.
However, this will compile because it is more explicit:
bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
Follow up to additional question, "But, in case I'm using a reference type, would the the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?"
I would have thought that == on the Generics would use the overloaded version, but the following test demonstrates otherwise. Interesting... I'd love to know why! If someone knows please share.
namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();
Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare<Test>(a, b);
}
static bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
}
class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}
public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}
Output
Inline:
Overloaded == called
Generic:
Press any key to continue . . .
Follow Up 2
I do want to point out that changing my compare method to
static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}
causes the overloaded == operator to be called. I guess without specifying the type (as a where), the compiler can't infer that it should use the overloaded operator... though I'd think that it would have enough information to make that decision even without specifying the type.

In general, EqualityComparer<T>.Default.Equals should do the job with anything that implements IEquatable<T>, or that has a sensible Equals implementation.
If, however, == and Equals are implemented differently for some reason, then my work on generic operators should be useful; it supports the operator versions of (among others):
Equal(T value1, T value2)
NotEqual(T value1, T value2)
GreaterThan(T value1, T value2)
LessThan(T value1, T value2)
GreaterThanOrEqual(T value1, T value2)
LessThanOrEqual(T value1, T value2)

So many answers, and not a single one explains the WHY? (which Giovanni explicitly asked)...
.NET generics do not act like C++ templates. In C++ templates, overload resolution occurs after the actual template parameters are known.
In .NET generics (including C#), overload resolution occurs without knowing the actual generic parameters. The only information the compiler can use to choose the function to call comes from type constraints on the generic parameters.

The compile can't know T couldn't be a struct (value type). So you have to tell it it can only be of reference type i think:
bool Compare<T>(T x, T y) where T : class { return x == y; }
It's because if T could be a value type, there could be cases where x == y would be ill formed - in cases when a type doesn't have an operator == defined. The same will happen for this which is more obvious:
void CallFoo<T>(T x) { x.foo(); }
That fails too, because you could pass a type T that wouldn't have a function foo. C# forces you to make sure all possible types always have a function foo. That's done by the where clause.

It appears that without the class constraint:
bool Compare<T> (T x, T y) where T: class
{
return x == y;
}
One should realize that while class constrained Equals in the == operator inherits from Object.Equals, while that of a struct overrides ValueType.Equals.
Note that:
bool Compare<T> (T x, T y) where T: struct
{
return x == y;
}
also gives out the same compiler error.
As yet I do not understand why having a value type equality operator comparison is rejected by the compiler. I do know for a fact though, that this works:
bool Compare<T> (T x, T y)
{
return x.Equals(y);
}

Well in my case I wanted to unit-test the equality operator. I needed call the code under the equality operators without explicitly setting the generic type. Advises for EqualityComparer were not helpful as EqualityComparer called Equals method but not the equality operator.
Here is how I've got this working with generic types by building a LINQ. It calls the right code for == and != operators:
/// <summary>
/// Gets the result of "a == b"
/// </summary>
public bool GetEqualityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.Equal(paramA, paramB);
// compile it
var invokeEqualityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeEqualityOperator(a, b);
}
/// <summary>
/// Gets the result of "a =! b"
/// </summary>
public bool GetInequalityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.NotEqual(paramA, paramB);
// compile it
var invokeInequalityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeInequalityOperator(a, b);
}

There is an MSDN Connect entry for this here
Alex Turner's reply starts with:
Unfortunately, this behavior is by
design and there is not an easy
solution to enable use of == with type
parameters that may contain value
types.

If you want to make sure the operators of your custom type are called you can do so via reflection. Just get the type using your generic parameter and retrieve the MethodInfo for the desired operator (e.g. op_Equality, op_Inequality, op_LessThan...).
var methodInfo = typeof (T).GetMethod("op_Equality",
BindingFlags.Static | BindingFlags.Public);
Then execute the operator using the MethodInfo's Invoke method and pass in the objects as the parameters.
var result = (bool) methodInfo.Invoke(null, new object[] { object1, object2});
This will invoke your overloaded operator and not the one defined by the constraints applied on the generic parameter. Might not be practical, but could come in handy for unit testing your operators when using a generic base class that contains a couple of tests.

I wrote the following function looking at the latest msdn. It can easily compare two objects x and y:
static bool IsLessThan(T x, T y)
{
return ((IComparable)(x)).CompareTo(y) <= 0;
}

bool Compare(T x, T y) where T : class { return x == y; }
The above will work because == is taken care of in case of user-defined reference types.
In case of value types, == can be overridden. In which case, "!=" should also be defined.
I think that could be the reason, it disallows generic comparison using "==".

The .Equals() works for me while TKey is a generic type.
public virtual TOutputDto GetOne(TKey id)
{
var entity =
_unitOfWork.BaseRepository
.FindByCondition(x =>
!x.IsDelete &&
x.Id.Equals(id))
.SingleOrDefault();
// ...
}

I have 2 solutions and they're very simply.
Solution 1: Cast the generic typed variable to object and use == operator.
Example:
void Foo<T>(T t1, T t2)
{
object o1 = t1;
object o2 = t2;
if (o1 == o2)
{
// ...
// ..
// .
}
}
Solution 2: Use object.Equals(object, object) method.
Example:
void Foo<T>(T t1, T t2)
{
if (object.Equals(t1, t2)
{
// ...
// ..
// .
}
}

You can do this with C# 11 and .NET 7+:
static void Main()
{
Console.WriteLine(Compare(2, 2));
Console.WriteLine(Compare(2, 3));
}
static bool Compare<T>(T x, T y) where T : IEqualityOperators<T, T, bool>
{
return x == y;
}
(you may prefer to use where T : INumber<T>, which covers this scenario and a lot more, but it depends on your specific needs; not all equatable types are numbers)

Related

Call double "==" operator when used as generic parameter [duplicate]

According to the documentation of the == operator in MSDN,
For predefined value types, the
equality operator (==) returns true if
the values of its operands are equal,
false otherwise. For reference types
other than string, == returns true if
its two operands refer to the same
object. For the string type, ==
compares the values of the strings.
User-defined value types can overload
the == operator (see operator). So can
user-defined reference types, although
by default == behaves as described
above for both predefined and
user-defined reference types.
So why does this code snippet fail to compile?
bool Compare<T>(T x, T y) { return x == y; }
I get the error Operator '==' cannot be applied to operands of type 'T' and 'T'. I wonder why, since as far as I understand the == operator is predefined for all types?
Edit: Thanks, everybody. I didn't notice at first that the statement was about reference types only. I also thought that bit-by-bit comparison is provided for all value types, which I now know is not correct.
But, in case I'm using a reference type, would the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?
Edit 2: Through trial and error, we learned that the == operator will use the predefined reference comparison when using an unrestricted generic type. Actually, the compiler will use the best method it can find for the restricted type argument, but will look no further. For example, the code below will always print true, even when Test.test<B>(new B(), new B()) is called:
class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test<T>(T a, T b) where T : A { Console.WriteLine(a == b); } }
As others have said, it will only work when T is constrained to be a reference type. Without any constraints, you can compare with null, but only null - and that comparison will always be false for non-nullable value types.
Instead of calling Equals, it's better to use an IComparer<T> - and if you have no more information, EqualityComparer<T>.Default is a good choice:
public bool Compare<T>(T x, T y)
{
return EqualityComparer<T>.Default.Equals(x, y);
}
Aside from anything else, this avoids boxing/casting.
"...by default == behaves as described above for both predefined and user-defined reference types."
Type T is not necessarily a reference type, so the compiler can't make that assumption.
However, this will compile because it is more explicit:
bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
Follow up to additional question, "But, in case I'm using a reference type, would the the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?"
I would have thought that == on the Generics would use the overloaded version, but the following test demonstrates otherwise. Interesting... I'd love to know why! If someone knows please share.
namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();
Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare<Test>(a, b);
}
static bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
}
class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}
public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}
Output
Inline:
Overloaded == called
Generic:
Press any key to continue . . .
Follow Up 2
I do want to point out that changing my compare method to
static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}
causes the overloaded == operator to be called. I guess without specifying the type (as a where), the compiler can't infer that it should use the overloaded operator... though I'd think that it would have enough information to make that decision even without specifying the type.
In general, EqualityComparer<T>.Default.Equals should do the job with anything that implements IEquatable<T>, or that has a sensible Equals implementation.
If, however, == and Equals are implemented differently for some reason, then my work on generic operators should be useful; it supports the operator versions of (among others):
Equal(T value1, T value2)
NotEqual(T value1, T value2)
GreaterThan(T value1, T value2)
LessThan(T value1, T value2)
GreaterThanOrEqual(T value1, T value2)
LessThanOrEqual(T value1, T value2)
So many answers, and not a single one explains the WHY? (which Giovanni explicitly asked)...
.NET generics do not act like C++ templates. In C++ templates, overload resolution occurs after the actual template parameters are known.
In .NET generics (including C#), overload resolution occurs without knowing the actual generic parameters. The only information the compiler can use to choose the function to call comes from type constraints on the generic parameters.
The compile can't know T couldn't be a struct (value type). So you have to tell it it can only be of reference type i think:
bool Compare<T>(T x, T y) where T : class { return x == y; }
It's because if T could be a value type, there could be cases where x == y would be ill formed - in cases when a type doesn't have an operator == defined. The same will happen for this which is more obvious:
void CallFoo<T>(T x) { x.foo(); }
That fails too, because you could pass a type T that wouldn't have a function foo. C# forces you to make sure all possible types always have a function foo. That's done by the where clause.
It appears that without the class constraint:
bool Compare<T> (T x, T y) where T: class
{
return x == y;
}
One should realize that while class constrained Equals in the == operator inherits from Object.Equals, while that of a struct overrides ValueType.Equals.
Note that:
bool Compare<T> (T x, T y) where T: struct
{
return x == y;
}
also gives out the same compiler error.
As yet I do not understand why having a value type equality operator comparison is rejected by the compiler. I do know for a fact though, that this works:
bool Compare<T> (T x, T y)
{
return x.Equals(y);
}
Well in my case I wanted to unit-test the equality operator. I needed call the code under the equality operators without explicitly setting the generic type. Advises for EqualityComparer were not helpful as EqualityComparer called Equals method but not the equality operator.
Here is how I've got this working with generic types by building a LINQ. It calls the right code for == and != operators:
/// <summary>
/// Gets the result of "a == b"
/// </summary>
public bool GetEqualityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.Equal(paramA, paramB);
// compile it
var invokeEqualityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeEqualityOperator(a, b);
}
/// <summary>
/// Gets the result of "a =! b"
/// </summary>
public bool GetInequalityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.NotEqual(paramA, paramB);
// compile it
var invokeInequalityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeInequalityOperator(a, b);
}
There is an MSDN Connect entry for this here
Alex Turner's reply starts with:
Unfortunately, this behavior is by
design and there is not an easy
solution to enable use of == with type
parameters that may contain value
types.
If you want to make sure the operators of your custom type are called you can do so via reflection. Just get the type using your generic parameter and retrieve the MethodInfo for the desired operator (e.g. op_Equality, op_Inequality, op_LessThan...).
var methodInfo = typeof (T).GetMethod("op_Equality",
BindingFlags.Static | BindingFlags.Public);
Then execute the operator using the MethodInfo's Invoke method and pass in the objects as the parameters.
var result = (bool) methodInfo.Invoke(null, new object[] { object1, object2});
This will invoke your overloaded operator and not the one defined by the constraints applied on the generic parameter. Might not be practical, but could come in handy for unit testing your operators when using a generic base class that contains a couple of tests.
I wrote the following function looking at the latest msdn. It can easily compare two objects x and y:
static bool IsLessThan(T x, T y)
{
return ((IComparable)(x)).CompareTo(y) <= 0;
}
bool Compare(T x, T y) where T : class { return x == y; }
The above will work because == is taken care of in case of user-defined reference types.
In case of value types, == can be overridden. In which case, "!=" should also be defined.
I think that could be the reason, it disallows generic comparison using "==".
The .Equals() works for me while TKey is a generic type.
public virtual TOutputDto GetOne(TKey id)
{
var entity =
_unitOfWork.BaseRepository
.FindByCondition(x =>
!x.IsDelete &&
x.Id.Equals(id))
.SingleOrDefault();
// ...
}
I have 2 solutions and they're very simply.
Solution 1: Cast the generic typed variable to object and use == operator.
Example:
void Foo<T>(T t1, T t2)
{
object o1 = t1;
object o2 = t2;
if (o1 == o2)
{
// ...
// ..
// .
}
}
Solution 2: Use object.Equals(object, object) method.
Example:
void Foo<T>(T t1, T t2)
{
if (object.Equals(t1, t2)
{
// ...
// ..
// .
}
}
You can do this with C# 11 and .NET 7+:
static void Main()
{
Console.WriteLine(Compare(2, 2));
Console.WriteLine(Compare(2, 3));
}
static bool Compare<T>(T x, T y) where T : IEqualityOperators<T, T, bool>
{
return x == y;
}
(you may prefer to use where T : INumber<T>, which covers this scenario and a lot more, but it depends on your specific needs; not all equatable types are numbers)

C# operator '==' cannot be applied to operands of type 'TKey' and 'TKey' in generic classes [duplicate]

According to the documentation of the == operator in MSDN,
For predefined value types, the
equality operator (==) returns true if
the values of its operands are equal,
false otherwise. For reference types
other than string, == returns true if
its two operands refer to the same
object. For the string type, ==
compares the values of the strings.
User-defined value types can overload
the == operator (see operator). So can
user-defined reference types, although
by default == behaves as described
above for both predefined and
user-defined reference types.
So why does this code snippet fail to compile?
bool Compare<T>(T x, T y) { return x == y; }
I get the error Operator '==' cannot be applied to operands of type 'T' and 'T'. I wonder why, since as far as I understand the == operator is predefined for all types?
Edit: Thanks, everybody. I didn't notice at first that the statement was about reference types only. I also thought that bit-by-bit comparison is provided for all value types, which I now know is not correct.
But, in case I'm using a reference type, would the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?
Edit 2: Through trial and error, we learned that the == operator will use the predefined reference comparison when using an unrestricted generic type. Actually, the compiler will use the best method it can find for the restricted type argument, but will look no further. For example, the code below will always print true, even when Test.test<B>(new B(), new B()) is called:
class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test<T>(T a, T b) where T : A { Console.WriteLine(a == b); } }
As others have said, it will only work when T is constrained to be a reference type. Without any constraints, you can compare with null, but only null - and that comparison will always be false for non-nullable value types.
Instead of calling Equals, it's better to use an IComparer<T> - and if you have no more information, EqualityComparer<T>.Default is a good choice:
public bool Compare<T>(T x, T y)
{
return EqualityComparer<T>.Default.Equals(x, y);
}
Aside from anything else, this avoids boxing/casting.
"...by default == behaves as described above for both predefined and user-defined reference types."
Type T is not necessarily a reference type, so the compiler can't make that assumption.
However, this will compile because it is more explicit:
bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
Follow up to additional question, "But, in case I'm using a reference type, would the the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?"
I would have thought that == on the Generics would use the overloaded version, but the following test demonstrates otherwise. Interesting... I'd love to know why! If someone knows please share.
namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();
Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare<Test>(a, b);
}
static bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
}
class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}
public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}
Output
Inline:
Overloaded == called
Generic:
Press any key to continue . . .
Follow Up 2
I do want to point out that changing my compare method to
static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}
causes the overloaded == operator to be called. I guess without specifying the type (as a where), the compiler can't infer that it should use the overloaded operator... though I'd think that it would have enough information to make that decision even without specifying the type.
In general, EqualityComparer<T>.Default.Equals should do the job with anything that implements IEquatable<T>, or that has a sensible Equals implementation.
If, however, == and Equals are implemented differently for some reason, then my work on generic operators should be useful; it supports the operator versions of (among others):
Equal(T value1, T value2)
NotEqual(T value1, T value2)
GreaterThan(T value1, T value2)
LessThan(T value1, T value2)
GreaterThanOrEqual(T value1, T value2)
LessThanOrEqual(T value1, T value2)
So many answers, and not a single one explains the WHY? (which Giovanni explicitly asked)...
.NET generics do not act like C++ templates. In C++ templates, overload resolution occurs after the actual template parameters are known.
In .NET generics (including C#), overload resolution occurs without knowing the actual generic parameters. The only information the compiler can use to choose the function to call comes from type constraints on the generic parameters.
The compile can't know T couldn't be a struct (value type). So you have to tell it it can only be of reference type i think:
bool Compare<T>(T x, T y) where T : class { return x == y; }
It's because if T could be a value type, there could be cases where x == y would be ill formed - in cases when a type doesn't have an operator == defined. The same will happen for this which is more obvious:
void CallFoo<T>(T x) { x.foo(); }
That fails too, because you could pass a type T that wouldn't have a function foo. C# forces you to make sure all possible types always have a function foo. That's done by the where clause.
It appears that without the class constraint:
bool Compare<T> (T x, T y) where T: class
{
return x == y;
}
One should realize that while class constrained Equals in the == operator inherits from Object.Equals, while that of a struct overrides ValueType.Equals.
Note that:
bool Compare<T> (T x, T y) where T: struct
{
return x == y;
}
also gives out the same compiler error.
As yet I do not understand why having a value type equality operator comparison is rejected by the compiler. I do know for a fact though, that this works:
bool Compare<T> (T x, T y)
{
return x.Equals(y);
}
Well in my case I wanted to unit-test the equality operator. I needed call the code under the equality operators without explicitly setting the generic type. Advises for EqualityComparer were not helpful as EqualityComparer called Equals method but not the equality operator.
Here is how I've got this working with generic types by building a LINQ. It calls the right code for == and != operators:
/// <summary>
/// Gets the result of "a == b"
/// </summary>
public bool GetEqualityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.Equal(paramA, paramB);
// compile it
var invokeEqualityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeEqualityOperator(a, b);
}
/// <summary>
/// Gets the result of "a =! b"
/// </summary>
public bool GetInequalityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.NotEqual(paramA, paramB);
// compile it
var invokeInequalityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeInequalityOperator(a, b);
}
There is an MSDN Connect entry for this here
Alex Turner's reply starts with:
Unfortunately, this behavior is by
design and there is not an easy
solution to enable use of == with type
parameters that may contain value
types.
If you want to make sure the operators of your custom type are called you can do so via reflection. Just get the type using your generic parameter and retrieve the MethodInfo for the desired operator (e.g. op_Equality, op_Inequality, op_LessThan...).
var methodInfo = typeof (T).GetMethod("op_Equality",
BindingFlags.Static | BindingFlags.Public);
Then execute the operator using the MethodInfo's Invoke method and pass in the objects as the parameters.
var result = (bool) methodInfo.Invoke(null, new object[] { object1, object2});
This will invoke your overloaded operator and not the one defined by the constraints applied on the generic parameter. Might not be practical, but could come in handy for unit testing your operators when using a generic base class that contains a couple of tests.
I wrote the following function looking at the latest msdn. It can easily compare two objects x and y:
static bool IsLessThan(T x, T y)
{
return ((IComparable)(x)).CompareTo(y) <= 0;
}
bool Compare(T x, T y) where T : class { return x == y; }
The above will work because == is taken care of in case of user-defined reference types.
In case of value types, == can be overridden. In which case, "!=" should also be defined.
I think that could be the reason, it disallows generic comparison using "==".
The .Equals() works for me while TKey is a generic type.
public virtual TOutputDto GetOne(TKey id)
{
var entity =
_unitOfWork.BaseRepository
.FindByCondition(x =>
!x.IsDelete &&
x.Id.Equals(id))
.SingleOrDefault();
// ...
}
I have 2 solutions and they're very simply.
Solution 1: Cast the generic typed variable to object and use == operator.
Example:
void Foo<T>(T t1, T t2)
{
object o1 = t1;
object o2 = t2;
if (o1 == o2)
{
// ...
// ..
// .
}
}
Solution 2: Use object.Equals(object, object) method.
Example:
void Foo<T>(T t1, T t2)
{
if (object.Equals(t1, t2)
{
// ...
// ..
// .
}
}
You can do this with C# 11 and .NET 7+:
static void Main()
{
Console.WriteLine(Compare(2, 2));
Console.WriteLine(Compare(2, 3));
}
static bool Compare<T>(T x, T y) where T : IEqualityOperators<T, T, bool>
{
return x == y;
}
(you may prefer to use where T : INumber<T>, which covers this scenario and a lot more, but it depends on your specific needs; not all equatable types are numbers)

C# Equality check for generic wrapper with implicit cast doesn't work for classes [duplicate]

Some code for context:
class a
{
}
class b
{
public a a{get;set;}
public static implicit operator a(b b)
{
return b.a;
}
}
a a=null;
b b=null;
a = b;
//compiler: cannot apply operator '==' to operands of type tralala...
bool c = a == b;
Is it possible to use == operator on different type instances, where one can implicitly convert to another? What did i miss?
Edit:
If types must be the same calling ==, then why
int a=1;
double b=1;
bool c=a==b;
works?
The implicit operator only works for assignment.
You want to overload the equality (==) operator, as such:
class a
{
public static bool operator ==(a x, b y)
{
return x == y.a;
}
public static bool operator !=(a x, b y)
{
return !(x == y);
}
}
class b
{
public a a{get;set;}
public static implicit operator a(b b)
{
return b.a;
}
}
This should then allow you to compare two objects of type a and b as suggested in your post.
var x = new a();
var y = new b();
bool c = (x == y); // compiles
Note:
I recommmend simply overriding the GetHashCode and Equals method, as the compiler warns, but as you seem to want to supress them, you can do that as follows.
Change your class declaration of a to:
#pragma warning disable 0660, 0661
class a
#pragma warning restore 0660, 0661
{
// ...
}
Is it possible to use == operator on
different type instances, where one
can implicitly convert to another?
Yes.
What did i miss?
Here's the relevant portion of the specification. You missed the highlighted word.
The predefined reference type equality
operators require [that] both operands
are reference-type values or the
literal null. Furthermore, a standard
implicit conversion exists from the
type of either operand to the type of
the other operand.
A user-defined conversion is by definition not a standard conversion. These are reference types. Therefore, the predefined reference type equality operator is not a candidate.
If types must be the same calling ==,
then why [double == int] works?
Your supposition that the types must be the same is incorrect. There is a standard implicit conversion from int to double and there is an equality operator that takes two doubles, so this works.
I think you also missed this bit:
It is a compile-time error to use the
predefined reference type equality
operators to compare two references
that are known to be different at
compile-time. For example, if the
compile-time types of the operands are
two class types A and B, and if
neither A nor B derives from the
other, then it would be impossible for
the two operands to reference the same
object. Thus, the operation is
considered a compile-time error.
I would imagine that you need to actually override the == operator for the types you are interested in. Whether the compile/runtime will still complain even if the types are implicity convertable is something you'll have to experiment with.
public static bool operator ==(a a, b b)
{
//Need this check or we can't do obj == null in our Equals implementation
if (((Object)a) == null)
{
return false;
}
else
{
return a.Equals(b);
}
}
Alternatively just use Equals implementations like ole6ka suggests and ensure that the implementation does the type casting you need.
http://msdn.microsoft.com/en-us/library/8edha89s.aspx
In each case, one parameter must be
the same type as the class or struct
that declares the operator (...)
Use this
bool c = a.Equals(b);

Direct Comparison Behavior in Generics [duplicate]

According to the documentation of the == operator in MSDN,
For predefined value types, the
equality operator (==) returns true if
the values of its operands are equal,
false otherwise. For reference types
other than string, == returns true if
its two operands refer to the same
object. For the string type, ==
compares the values of the strings.
User-defined value types can overload
the == operator (see operator). So can
user-defined reference types, although
by default == behaves as described
above for both predefined and
user-defined reference types.
So why does this code snippet fail to compile?
bool Compare<T>(T x, T y) { return x == y; }
I get the error Operator '==' cannot be applied to operands of type 'T' and 'T'. I wonder why, since as far as I understand the == operator is predefined for all types?
Edit: Thanks, everybody. I didn't notice at first that the statement was about reference types only. I also thought that bit-by-bit comparison is provided for all value types, which I now know is not correct.
But, in case I'm using a reference type, would the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?
Edit 2: Through trial and error, we learned that the == operator will use the predefined reference comparison when using an unrestricted generic type. Actually, the compiler will use the best method it can find for the restricted type argument, but will look no further. For example, the code below will always print true, even when Test.test<B>(new B(), new B()) is called:
class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test<T>(T a, T b) where T : A { Console.WriteLine(a == b); } }
As others have said, it will only work when T is constrained to be a reference type. Without any constraints, you can compare with null, but only null - and that comparison will always be false for non-nullable value types.
Instead of calling Equals, it's better to use an IComparer<T> - and if you have no more information, EqualityComparer<T>.Default is a good choice:
public bool Compare<T>(T x, T y)
{
return EqualityComparer<T>.Default.Equals(x, y);
}
Aside from anything else, this avoids boxing/casting.
"...by default == behaves as described above for both predefined and user-defined reference types."
Type T is not necessarily a reference type, so the compiler can't make that assumption.
However, this will compile because it is more explicit:
bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
Follow up to additional question, "But, in case I'm using a reference type, would the the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?"
I would have thought that == on the Generics would use the overloaded version, but the following test demonstrates otherwise. Interesting... I'd love to know why! If someone knows please share.
namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();
Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare<Test>(a, b);
}
static bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
}
class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}
public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}
Output
Inline:
Overloaded == called
Generic:
Press any key to continue . . .
Follow Up 2
I do want to point out that changing my compare method to
static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}
causes the overloaded == operator to be called. I guess without specifying the type (as a where), the compiler can't infer that it should use the overloaded operator... though I'd think that it would have enough information to make that decision even without specifying the type.
In general, EqualityComparer<T>.Default.Equals should do the job with anything that implements IEquatable<T>, or that has a sensible Equals implementation.
If, however, == and Equals are implemented differently for some reason, then my work on generic operators should be useful; it supports the operator versions of (among others):
Equal(T value1, T value2)
NotEqual(T value1, T value2)
GreaterThan(T value1, T value2)
LessThan(T value1, T value2)
GreaterThanOrEqual(T value1, T value2)
LessThanOrEqual(T value1, T value2)
So many answers, and not a single one explains the WHY? (which Giovanni explicitly asked)...
.NET generics do not act like C++ templates. In C++ templates, overload resolution occurs after the actual template parameters are known.
In .NET generics (including C#), overload resolution occurs without knowing the actual generic parameters. The only information the compiler can use to choose the function to call comes from type constraints on the generic parameters.
The compile can't know T couldn't be a struct (value type). So you have to tell it it can only be of reference type i think:
bool Compare<T>(T x, T y) where T : class { return x == y; }
It's because if T could be a value type, there could be cases where x == y would be ill formed - in cases when a type doesn't have an operator == defined. The same will happen for this which is more obvious:
void CallFoo<T>(T x) { x.foo(); }
That fails too, because you could pass a type T that wouldn't have a function foo. C# forces you to make sure all possible types always have a function foo. That's done by the where clause.
It appears that without the class constraint:
bool Compare<T> (T x, T y) where T: class
{
return x == y;
}
One should realize that while class constrained Equals in the == operator inherits from Object.Equals, while that of a struct overrides ValueType.Equals.
Note that:
bool Compare<T> (T x, T y) where T: struct
{
return x == y;
}
also gives out the same compiler error.
As yet I do not understand why having a value type equality operator comparison is rejected by the compiler. I do know for a fact though, that this works:
bool Compare<T> (T x, T y)
{
return x.Equals(y);
}
Well in my case I wanted to unit-test the equality operator. I needed call the code under the equality operators without explicitly setting the generic type. Advises for EqualityComparer were not helpful as EqualityComparer called Equals method but not the equality operator.
Here is how I've got this working with generic types by building a LINQ. It calls the right code for == and != operators:
/// <summary>
/// Gets the result of "a == b"
/// </summary>
public bool GetEqualityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.Equal(paramA, paramB);
// compile it
var invokeEqualityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeEqualityOperator(a, b);
}
/// <summary>
/// Gets the result of "a =! b"
/// </summary>
public bool GetInequalityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.NotEqual(paramA, paramB);
// compile it
var invokeInequalityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeInequalityOperator(a, b);
}
There is an MSDN Connect entry for this here
Alex Turner's reply starts with:
Unfortunately, this behavior is by
design and there is not an easy
solution to enable use of == with type
parameters that may contain value
types.
If you want to make sure the operators of your custom type are called you can do so via reflection. Just get the type using your generic parameter and retrieve the MethodInfo for the desired operator (e.g. op_Equality, op_Inequality, op_LessThan...).
var methodInfo = typeof (T).GetMethod("op_Equality",
BindingFlags.Static | BindingFlags.Public);
Then execute the operator using the MethodInfo's Invoke method and pass in the objects as the parameters.
var result = (bool) methodInfo.Invoke(null, new object[] { object1, object2});
This will invoke your overloaded operator and not the one defined by the constraints applied on the generic parameter. Might not be practical, but could come in handy for unit testing your operators when using a generic base class that contains a couple of tests.
I wrote the following function looking at the latest msdn. It can easily compare two objects x and y:
static bool IsLessThan(T x, T y)
{
return ((IComparable)(x)).CompareTo(y) <= 0;
}
bool Compare(T x, T y) where T : class { return x == y; }
The above will work because == is taken care of in case of user-defined reference types.
In case of value types, == can be overridden. In which case, "!=" should also be defined.
I think that could be the reason, it disallows generic comparison using "==".
The .Equals() works for me while TKey is a generic type.
public virtual TOutputDto GetOne(TKey id)
{
var entity =
_unitOfWork.BaseRepository
.FindByCondition(x =>
!x.IsDelete &&
x.Id.Equals(id))
.SingleOrDefault();
// ...
}
I have 2 solutions and they're very simply.
Solution 1: Cast the generic typed variable to object and use == operator.
Example:
void Foo<T>(T t1, T t2)
{
object o1 = t1;
object o2 = t2;
if (o1 == o2)
{
// ...
// ..
// .
}
}
Solution 2: Use object.Equals(object, object) method.
Example:
void Foo<T>(T t1, T t2)
{
if (object.Equals(t1, t2)
{
// ...
// ..
// .
}
}
You can do this with C# 11 and .NET 7+:
static void Main()
{
Console.WriteLine(Compare(2, 2));
Console.WriteLine(Compare(2, 3));
}
static bool Compare<T>(T x, T y) where T : IEqualityOperators<T, T, bool>
{
return x == y;
}
(you may prefer to use where T : INumber<T>, which covers this scenario and a lot more, but it depends on your specific needs; not all equatable types are numbers)

Why are generic and non-generic structs treated differently when building expression that lifts operator == to nullable?

This looks like a bug in lifting to null of operands on generic structs.
Consider the following dummy struct, that overrides operator==:
struct MyStruct
{
private readonly int _value;
public MyStruct(int val) { this._value = val; }
public override bool Equals(object obj) { return false; }
public override int GetHashCode() { return base.GetHashCode(); }
public static bool operator ==(MyStruct a, MyStruct b) { return false; }
public static bool operator !=(MyStruct a, MyStruct b) { return false; }
}
Now consider the following expressions:
Expression<Func<MyStruct, MyStruct, bool>> exprA =
(valueA, valueB) => valueA == valueB;
Expression<Func<MyStruct?, MyStruct?, bool>> exprB =
(nullableValueA, nullableValueB) => nullableValueA == nullableValueB;
Expression<Func<MyStruct?, MyStruct, bool>> exprC =
(nullableValueA, valueB) => nullableValueA == valueB;
All three compile and run as expected.
When they're compiled (using .Compile()) they produce the following code (paraphrased to English from the IL):
The first expression that takes only MyStruct (not nullable) args, simply calls op_Equality (our implementation of operator ==)
The second expression, when compiled, produces code that checks each argument to see if it HasValue. If both don't (both equal null), returns true. If only one has a value, returns false. Otherwise, calls op_Equality on the two values.
The third expression checks the nullable argument to see if it has a value - if not, returns false. Otherwise, calls op_Equality.
So far so good.
Next step: do the exact same thing with a generic type - change MyStruct to MyStruct<T> everywhere in the definition of the type, and change it to MyStruct<int> in the expressions.
Now the third expression compiles but throws a runtime exception InvalidOperationException with the following message:
The operands for operator 'Equal' do not match the parameters of method 'op_Equality'.
I would expect generic structs to behave exactly the same as non-generic ones, with all the nullable-lifting described above.
So my questions are:
Why is there a difference between generic and non-generic structs?
What is the meaning of this exception?
Is this a bug in C#/.NET?
The full code for reproducing this is available on this gist.
The short answer is: yes, that's a bug. I've put a minimal repro and a short analysis below.
My apologies. I wrote a lot of that code and so it was likely my bad.
I have sent a repro off to the Roslyn development, test and program management teams. I doubt this reproduces in Roslyn, but they'll verify that it does not and decide whether this makes the bar for a C# 5 service pack.
Feel free to enter an issue on connect.microsoft.com as well if you want it tracked there as well.
Minimal repro:
using System;
using System.Linq.Expressions;
struct S<T>
{
public static bool operator ==(S<T> a, S<T> b) { return false; }
public static bool operator !=(S<T> a, S<T> b) { return false; }
}
class Program
{
static void Main()
{
Expression<Func<S<int>?, S<int>, bool>> x = (a, b) => a == b;
}
}
The code that is generated in the minimal repro is equivalent to
ParameterExpression pa = Expression.Parameter(typeof(S<int>?), "a");
ParameterExpression pb = Expression.Parameter(typeof(S<int>), "b");
Expression.Lambda<Func<S<int>?, S<int>, bool>>(
Expression.Equal(pa, pb, false, infoof(S<int>.op_Equality)
new ParameterExpression[2] { pa, pb } );
Where infoof is a fake operator that gets a MethodInfo for the given method.
The correct code would be:
ParameterExpression pa = Expression.Parameter(typeof(S<int>?), "a");
ParameterExpression pb = Expression.Parameter(typeof(S<int>), "b");
Expression.Lambda<Func<S<int>?, S<int>, bool>>(
Expression.Equal(pa, Expression.Convert(pb, typeof(S<int>?), false, infoof(S<int>.op_Equality)
new ParameterExpression[2] { pa, pb } );
The Equal method cannot deal with one nullable, one non-nullable operands. It requires that either both are nullable or neither is.
(Note that the false is correct. This Boolean controls whether the result of a lifted equality is a lifted Boolean; in C# it is not, in VB it is.)
Yes, this bug is gone in Roslyn (the compiler under development). We'll see about the existing product.

Categories

Resources