Jasper Saaltink
Jasper Saaltink

Reputation: 149

IEqualityComparer for nullable struct

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

Answers (1)

Luaan
Luaan

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

Related Questions