EqualityComparer <T>.Дефо недостаточно умный - PullRequest
8 голосов
/ 29 апреля 2011

Я читал исходный код 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 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>.Default, EqualityComparer<MyEnum>.Default и EqualityComparer<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 для этого перечисления.Но почему enum не может основываться на long?Это не так сложно, я думаю?Есть особая причина?Создание сравнения как x == y не так сложно для enum, верно?Почему, наконец, он дает медленный ObjectEqualityComparer<T> для перечислений (даже он работает правильно)?

1 Ответ

6 голосов
/ 29 апреля 2011

Я думаю, что команде, ответственной за добавление этой функции, просто нет веских причин. Все функции имеют стоимость реализации, которая включает (среди прочего) время на документирование, кодирование и тестирование.

Есть несколько убедительных причин, по которым эта особенность пока не была выбрана среди других (и, вероятно, никогда не приведет к сокращению IMO):

  • Это применимо только к очень узкому сценарию (сравнение enums, подкрепленное чем-то отличным от int, и выполнение этого в некотором внутреннем цикле)
  • Существует очень простое и обнаруживаемое решение, если оно вызывает проблемы (напишите свой собственный компаратор)
...