Why do anonymous classes not implement System.IEquatable<T>?

51 Views Asked by At

Anonymous classes (a.k.a. anonymous types) are implicitly created and used by the C# compiler for code like this:

var obj = new { X1 = 0, X2 = 1 };

They have value equality semantics, i.e., the method bool Equals(object? obj) from the class object is overridden to perform field-by-field comparison. A typical C# class or struct T with value equality semantics implements the interface System.IEquatable<T>. The official guideline for how to implement equality also asserts that "both classes and structs require the same basic steps for implementing equality:

  1. Override the virtual Object.Equals(Object) method. In most cases, your implementation of bool Equals(object obj) should just call into the type-specific Equals method that is the implementation of the System.IEquatable<T> interface. (See step 2.)

  2. Implement the System.IEquatable<T> interface by providing a type-specific Equals method."

However, anonymous classes are compiled to something like this:

internal sealed class AnonymousType<T1, T2> {
    public T1 X1 { get; }
    public T2 X2 { get; }

    public AnonymousType(T1 x1, T2 x2) { X1 = x1; X2 = x2; }

    public override bool Equals(object? obj) {
        var other = obj as AnonymousType<T1, T2>;
        return this == other || (other != null &&
            EqualityComparer<T1>.Default.Equals(X1, other.X1) && 
            EqualityComparer<T2>.Default.Equals(X2, other.X2));
    }
    public override int GetHashCode() { /* code omitted */ }
    public override string ToString() { /* code omitted */ }
}

I would expect them to look more like this instead:

internal sealed class AnonymousType<T1, T2> : IEquatable<AnonymousType<T1, T2>> {
    public T1 X1 { get; }
    public T2 X2 { get; }

    public AnonymousType(T1 x1, T2 x2) { X1 = x1; X2 = x2; }

    public bool Equals(AnonymousType<T1, T2>? other) =>
        this == other || (other != null &&
        EqualityComparer<T1>.Default.Equals(X1, other.X1) && 
        EqualityComparer<T2>.Default.Equals(X2, other.X2));

    public override bool Equals(object? obj) =>
        Equals(obj as AnonymousType<T1, T2>);
    public override int GetHashCode() { /* code omitted */ }
    public override string ToString() { /* code omitted */ }
}

Perhaps, I would also add the == and != operators. (The guidelines say this is "optional but recommended".)

Is there any specific reason why anonymous classes do not implement IEquatable<T>, breaking the aforementioned guidelines?

0

There are 0 best solutions below