Reputation: 149
I want to write an equality comparer for Nullable structs. Lets say, DateTime?
.
So I come up with this code:
public class NullableEntityComparer<TEntity, TType> : IEqualityComparer<TEntity>
where TType : struct
where TEntity : Nullable<TType>
{
public bool Equals(TEntity x, TEntity y)
{
if(!x.HasValue && ! y.HasValue) return true;
if(x.HasValue && y.HasValue) return x.Value == y.Value;
return false;
}
public int GetHashCode(TEntity obj)
{
if (obj == null) throw new ArgumentNullException("obj");
if (obj.HasValue) return obj.Value.GetHashCode();
else return obj.GetHashCode();
}
}
The compiler doesn't like this and tells me:
'TType?' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
This is a clear message, however Nullable<T>
is a class, and TType?
is just a shorthand for Nullable<TType>
. Or am I missing something?
Why does this not work? And is there a solution to have an IEqualityComparer<T>
use the T.HasValue
property?
Upvotes: 3
Views: 1007
Reputation: 63742
It's quite simple - Nullable<>
is a struct
, so it counts as a sealed class, which is prohibited in a constraint (obviously - if you use a sealed class as a constraint, there's no need to use a generic type argument - you already always have exactly the same type).
But you don't need to do this at all. Simply have TType
constrained by struct
, but instead of using TEntity
, just use TType?
whenever you need the nullable:
public class NullableEntityComparer<TType> : IEqualityComparer<TType?>
where TType : struct
{
public bool Equals(TType? x, TType? y)
{
if(!x.HasValue && ! y.HasValue) return true;
if(x.HasValue && y.HasValue) return x.Value.Equals(y.Value);
return false;
}
public int GetHashCode(TType? obj)
{
return obj.GetHashCode();
}
}
As a side-note, nullables already have an implementation of equality that includes checking for nulls, so if you can avoid all this if you know the nullable type at compile-time.
Upvotes: 5