IEnumerable<T>: Can use Equals method but not equality operator

    public static IEnumerable<T> Method<T>(IEnumerable<T> iterable){

    T previous = default(T);
    foreach(T current in iterable){

        if (!current.Equals(previous)){

            previous = current;
            yield return current;
        }
    }
}

I don't have any questions about this code, but just why if it is possible to compare two objects of type T using:

if (!current.Equals(previous))

Then why is it not possible to compare using:

if (!current == previous)

The ! gives you an error saying

Operator '!' cannot be applied to operand of type 'T'

And if you remove that you get:

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

I gave up on a code challenge because it seemed to be telling me you literally can't compare one T to another. Then I found out you can do that but just with different syntax/using a specific method.

Can anyone advise why this would be please?


Solution 1:

.Equals is a part of System.Object. Right now there is no way to constrain a generic to have support for a specific operator overloading. You can however use IEquatable<T> or IEqualityComparer<T> to ensure the type implements its definition of equality.

Solution 2:

See this section of the language specification where == is specified. You can see that the language only has these overloads of == predefined:

bool operator ==(int x, int y);
bool operator ==(uint x, uint y);
bool operator ==(long x, long y);
bool operator ==(ulong x, ulong y);
bool operator ==(float x, float y);
bool operator ==(double x, double y);
bool operator ==(decimal x, decimal y);
bool operator ==(bool x, bool y);
bool operator ==(E x, E y); // for every enum E
bool operator ==(C x, C y); // for every class C
bool operator ==(string x, string y);
bool operator ==(System.Delegate x, System.Delegate y);

The type parameter T in your method is not constrained to anything, so what if it is, for example, a struct type? As you can see from the above list, there are no == operators defined for an arbitrary struct type.

If you add a T: class constraint, then you would be able to use == on it, because there is a == operator for all classes.

On the other hand, there is an Equals method declared in System.Object, from which every type in C# inherits from. Therefore, it is possible to use Equals on values of type T, even when T can be any type.