EqualityComparer< T> .DEFAULT不够聪明聪明、LT、EqualityComparer、DEFAULT

2023-09-04 01:15:57 作者:仗剑游

我读 EqualityComparer&LT的来源$ C ​​$ C; T> .DEFAULT ,发现它不是那么聪明。下面是一个例子:

I was reading the source code of EqualityComparer<T>.Default and found that it's not so clever. Here is an example:

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私有方法的来源$ C ​​$ C明显。

The reason is obvious from the source code of the private method in EqualityComparer.

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&LT; INT&GT; .DEFAULT EqualityComparer&LT; MyEnum&GT; .DEFAULT EqualityComparer&LT;长&GT; .DEFAULT 获得一个明智的比较器,其等于的方法是这样的:

We can see EqualityComparer<int>.Default,EqualityComparer<MyEnum>.Default and EqualityComparer<long>.Default get a wise comparer whose Equals method looks like:

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&LT; AnotherEnum&GT; .DEFAULT 是不吉利的,从方法,我们终于可以看到它得到 ObjectEqualityComparer&LT; T&GT;(),其等于办法大概是这样的:

The above two are clever, but EqualityComparer<AnotherEnum>.Default is unlucky, from the method we can see at last it gets a ObjectEqualityComparer<T>(), whose Equals method probably looks like:

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(三)== typeof运算(INT)是没有意义的,如果一个枚举的基础类型是int类型,该方法可转换的INT的默认比较于此枚举。但是,为什么不能枚举基于长?这不是那么难,我认为?任何特别的原因吗?构建像一个比较器x ==是不是这么难枚举,对不对?为什么最后它给出了一个缓慢的 ObjectEqualityComparer&LT; T&GT; 的枚举(即使它正常工作)

I think this condition Enum.GetUnderlyingType(c) == typeof(int) is pointless, if the underlying type of an enum is of type int, the method can convert the default comparer of int to this enum. But why can't an enum based on long? It's not so hard i think? Any special reason? Constructing a comparer like x == y isn't so hard for enum, right? Why at last it gives a slow ObjectEqualityComparer<T> for enums(even it works correctly)?

推荐答案

我认为,根本没有令人信服的理由,负责添加此功能的小组。所有的功能都实现成本,这包括(其中包括)来记录时间,code和测试。

I think that there's simply no compelling reason for the team responsible to add this feature. All features have an implementation cost which includes (among others) the time to document, code and test.

有几个令人信服的理由,为什么这个特殊的功能还没有被挑过别人,到目前为止(而且可能永远不会获得晋级IMO):

There are a couple of compelling reasons why this particular feature has not been picked over others so far (and will probably never make the cut IMO):

这仅适用于很窄的情况下(比较枚举一个不是 INT ,并做一些其他的支持在一些内环) 有一个非常简单的和发现的解决方案,如果它使你(写自己的比较器)问题 It only applies to a very narrow scenario (comparing enums backed by something other than an int, and doing that in some inner loop) There is a very straightforward and discoverable solution if it causes you a problem (write your own comparer)