我在阅读EqualityComparer<T>.Default的源代码,发现它不是那么聪明。这是一个例子:

enum MyEnum : int { A, B }
EqualityComparer<MyEnum>.Default.Equals(MyEnum.A, MyEnum.B)
//is as fast as
EqualityComparer<int>.Default.Equals(0, 1)

enum AnotherEnum : long { A = 1L, B = 2L }
//is 8x slower than
EqualityComparer<long>.Default.Equals(1L, 2L)

从EqualityComparer中的private方法的源代码中可以明显看出原因。
private static EqualityComparer<T> CreateComparer()
{
    //non-important codes are ignored
    if (c.IsEnum && (Enum.GetUnderlyingType(c) == typeof(int)))
    {
        return (EqualityComparer<T>) RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType) typeof(EnumEqualityComparer<int>), c);
    }
    return new ObjectEqualityComparer<T>();
}

我们可以看到EqualityComparer<int>.DefaultEqualityComparer<MyEnum>.DefaultEqualityComparer<long>.Default得到了一个明智的比较器,其Equals方法如下:
public static bool Equals(int x, int y)
{
    return x == y;  //or return x.Equals(y); here
                    //I'm not sure, but neither causes boxing
}

public static bool Equals(MyEnum x, MyEnum y)
{
    return x == y;  //it's impossible to use x.Equals(y) here
                    //because that causes boxing
}

上面的两个很聪明,但是EqualityComparer<AnotherEnum>.Default并不幸运,从我们最终可以看到的方法中,它得到了ObjectEqualityComparer<T>(),其Equals方法可能类似于:
public static bool Equals(AnotherEnum x, AnotherEnum y)
{
    return x.Equals(y);   //too bad, the Equals method is from System.Object
                       //and it's not override, boxing here!
                       //that's why it's so slow
}

我认为这种条件Enum.GetUnderlyingType(c) == typeof(int)是没有意义的,如果枚举的基础类型是int类型,则该方法可以将int的默认比较器转换为此枚举。但是,为什么不能基于长枚举?我觉得这并不难吗?有什么特殊原因吗?构造像x == y这样的比较器对于枚举来说并不难,对吧?为什么最后给枚举一个慢的ObjectEqualityComparer<T>(即使它可以正常工作)?

最佳答案

我认为,负责此功能的团队没有任何令人信服的理由。所有功能的实现成本都(其中包括)文档,代码和测试的时间。

有几个令人信服的理由说明为什么到目前为止尚未将此特定功能优先于其他功能(并且可能永远都不会削减IMO):

  • 它仅适用于非常狭窄的场景(比较由enums以外的东西支持的int,并在某些内部循环中进行此操作)
  • 如果它导致您遇到问题(编写自己的比较器),则有一个非常简单且可发现的解决方案

  • 10-08 18:43