I have a generic method defined like this:
public void MyMethod<T>(T myArgument)
The first thing I want to do is check if the value of myArgument is the default value for that type, something like this:
if (myArgument == default(T))
But this doesn't compile because I haven't guaranteed that T will implement the == operator. So I switched the code to this:
if (myArgument.Equals(default(T)))
Now this compiles, but will fail if myArgument is null, which is part of what I'm testing for. I can add an explicit null check like this:
if (myArgument == null || myArgument.Equals(default(T)))
Now this feels redundant to me. ReSharper is even suggesting that I change the myArgument == null part into myArgument == default(T) which is where I started. Is there a better way to solve this problem?
I need to support both references types and value types.
To avoid boxing, the best way to compare generics for equality is with
EqualityComparer<T>.Default
. This respectsIEquatable<T>
(without boxing) as well asobject.Equals
, and handles all theNullable<T>
"lifted" nuances. Hence:This will match:
Nullable<T>
I was able to locate a Microsoft Connect article that discusses this issue in some detail:
Here is what you can do...
I have validated that both of these methods work for a generic comparison of reference and value types:
or
To do comparisons with the "==" operator you will need to use one of these methods:
If all cases of T derive from a known base class you can let the compiler know using generic type restrictions.
The compiler then recognizes how to perform operations on
MyBase
and will not throw the "Operator '==' cannot be applied to operands of type 'T' and 'T'" error that you are seeing now.Another option would be to restrict T to any type that implements
IComparable
.And then use the
CompareTo
method defined by the IComparable interface.There is going to be a problem here -
If you're going to allow this to work for any type, default(T) will always be null for reference types, and 0 (or struct full of 0) for value types.
This is probably not the behavior you're after, though. If you want this to work in a generic way, you probably need to use reflection to check the type of T, and handle value types different than reference types.
Alternatively, you could put an interface constraint on this, and the interface could provide a way to check against the default of the class/struct.
@ilitirit:
Operator '==' cannot be applied to operands of type 'T' and 'T'
I can't think of a way to do this without the explicit null test followed by invoking the Equals method or object.Equals as suggested above.
You can devise a solution using System.Comparison but really that's going to end up with way more lines of code and increase complexity substantially.
Try this:
that should compile, and do what you want.
I think you were close.
Now this compiles, but will fail if
myArgument
is null, which is part of what I'm testing for. I can add an explicit null check like this:You just need to reverse the object on which the equals is being called for an elegant null-safe approach.