views:

117

answers:

2

I have the following code:

class Foo<T> where T : struct
{
    private T t;
    [...]
    public bool Equals(T t) { return this.t == t; }
}

When I try to compile, it gives me the following error:

Operator '==' cannot be applied to operands of type 'T' and 'T'

Why can't it be done? If the constraint was where T : class it would have worked. But I need it to be value type because in my implementation this generic will always be an enum.

What I am doing to circunvent the situation is using Object.Equals() method. Will it ensure the correct behavior all the time, since I am only comparing between T?

+3  A: 

This is an unpopular limitation of the constraints system. You cannot constrain a value type according to specific operations on it unless they are defined in an interface. So you cannot constrain for operator definitions, as they will not be defined on all value types, and the struct constraint allows any value type to be passed in.

struct A { }

That has no == defined, and yet your constraint says you'd be happy to accept it. So you cannot use ==.

The reason its different for reference types is because there is always a definition of == available for them (identity comparison).

The implementation of == on enum is close enough to the implementation of Equals that your workaround is fine.

Compare with the situation for > with numeric types! No such workaround there. The standard numbers have no interface with methods like GreaterThan, etc.

Daniel Earwicker
Hmm, I see... Thanks for all the clarification!
Ricardo Inácio
On your reference type note, keep in mind that `==` can't be *overridden*, but can be *overloaded*. Therefore a definition of `==` on a specific reference type will only be called when the operator is used on arguments statically known to derive from that type. With just a `class` constraint on a generic method, this means that `==` is *always* identity comparison.
kvb
@kvb - You're right, I've removed the "unless overridden" given that was both poorly worded and irrelevant here anyway.
Daniel Earwicker
+1  A: 

Have a look at this article by Jon Skeet and Marc Gravell. It describes an implementation of "generic operators" using Linq expressions. The actual implementation is available in the MiscUtil library

Thomas Levesque
It's a great article, but surely overkill when merely comparing for equality - the .NET framework already provides a universal method name for that, `Equals`, so it can be used on all types. Hence the OP's workaround is fine and guaranteed to work for any other type arguments too. For more number-related operators, the Linq expressions approach is very clever, but it does introduce a type hole.
Daniel Earwicker