.NET: Где находится реализация по умолчанию для "==" op_Equality () для типов значений? - PullRequest
0 голосов
/ 13 мая 2009

Я копался в .NET Reflector и заметил, что для ссылочных типов, таких как, например, "String", существует явная перегрузка оператора "==":

typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)

возвращает: System.Reflection.MethodInfo для оператора "==".

Благодаря его реализации вы не можете делать такие вещи, как:

if("hi" == 3)  // compiler error, plus code would throw an exception even if it ran)

Однако то же самое работает для типов значений:

if((int)1 == (float)1.0)  // correctly returns true
if((int)1 == (float)1.2)  // correctly returns false

Я пытаюсь выяснить, как именно .NET внутренне обрабатывает процесс преобразования типов, поэтому я искал реализацию op_Equality () в .NET Reflector, но у "int" его нет.

typeof(int).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)

возвращает ноль.

Так где же реализация по умолчанию для оператора "==" для типов значений? Я хотел бы иметь возможность назвать это через отражение:

public bool AreEqual(object x, object y)
{
    if(x.GetType().IsValueType && y.GetType().IsValueType)
        return x == y; // Incorrect, this calls the "object" equality override
    else
        ...
}

Редактировать # 1:

Я попробовал это, но это не сработало:

(int)1 == (float)1;                          // returns true
System.ValueType.Equals( (int)1, (float)1 ); // returns false

Редактировать # 2:

Тоже пробовал, но без любви:

object x = (int)1;
object y = (float)1.0;

bool b1 = (x == y);                 // b1 = false
bool b2 = ((ValueType)x).Equals(y); // b2 = false

Я полагаю, что этот оператор .Equals на ValueType не работает из-за проверки этого типа (извлечено из .NET Reflector):

ValueType.Equals(object obj)
{
    ...

    RuntimeType type = (RuntimeType) base.GetType();
    RuntimeType type2 = (RuntimeType) obj.GetType();
    if (type2 != type)
    {
        return false;
    }

    ...

Ответы [ 5 ]

2 голосов
/ 17 января 2013

Где реализация по умолчанию для == op_Equality для типов значений?

Нет значения по умолчанию == для типов значений. Попробуйте написать свой собственный тип значения

struct JustAnotherValueType
{
  public readonly int Field;
  public JustAnotherValueType(int f) { Field = f; }
}

Сделайте два значения x и y вашего типа. Попробуйте сказать x == y с ними. Это не скомпилируется. Вы можете сказать

(object)x == (object)y

, но при этом выполняется бокс x (назовем его боксом 1) и бокс y (бокс 2), а затем выполняется сравнение ссылок для двух блоков. Следовательно, он всегда будет возвращать false. И поэтому это бесполезно, и именно поэтому перегрузка ==(object x, object y) не выбирается автоматически при использовании == между двумя JustAnotherValueType.

Так что же происходит с int и float? Вы можете сравнить их с == в C #, и у них нет метода op_Equality ?! Объяснение состоит в том, что эти перегрузки определяются Спецификацией языка C # . См. Разделы Операторы сравнения целых чисел и Операторы сравнения с плавающей точкой .

Таким образом, факт заключается в том, что, хотя эти операторы не существуют как члены структур .NET, Спецификация языка C # определяет их, и компилятор C # должен создать некоторый действительный IL для имитации их поведения.

Кстати, System.Object тоже не имеет op_Equality. Это тоже определяется только C #. См. Раздел Операторы равенства типов ссылок . Обратите внимание, что System.Object имеет метод ReferenceEquals, который компилятор может выбрать для преобразования этой перегрузки == в. Также обратите внимание, что этот раздел спецификации содержит ограничения, так что x == y никогда не будет выполнять бокс на x или y.

А как насчет типов значений, таких как DateTime, TimeSpan и Guid, которые не упомянуты в спецификации C #, но для которых разрешено использовать ==? Ответ: у этих до есть член op_Equality.

Заключение: Спецификация языка C # определяет множество == перегрузок, которые требуются для реализации C #, и некоторые из этих перегрузок включают int и float и object.

Примечание: Метод виртуального экземпляра Equals(object) определен в object и унаследован всеми типами значений. Для структур, которые сами не переопределяют этот метод, используется override в System.ValueType. Сравнивает по значению. Так что с x и y, как указано выше, x.Equals(y) будет работать нормально. Equals - это метод виртуального экземпляра. С другой стороны, == - это static «метод», для которого выполняется разрешение перегрузки на основе типов времени компиляции двух операндов (без «виртуальной отправки»).

2 голосов
/ 13 мая 2009

оценка (int) 1 == (float) 1.0 не зависит от какого-либо специального оператора ==, только от правил преобразования.

Компилятор превратит это в (float) ((int) 1) == (float) 1.0

Edit: Правила указаны на MSDN .

2 голосов
/ 13 мая 2009

То, что вы ищете, это ValueType.Equals

Во многих случаях это просто делает побитовое сравнение значений. В некоторых случаях, хотя он будет использовать отражение для проверки полей.

РЕДАКТИРОВАТЬ

Вы путаете, как C # сравнивает типы значений и как .Net сравнивает типы значений. ValueType.Equals - это функция в .Net, используемая для сравнения объектов типа значения, имеющих одинаковый тип. C # будет выдавать код, который в конечном итоге вызывает эту функцию. Но он не называет это «int» и «float». Вместо этого он сначала преобразует их оба в тип, который не теряет точность ни для одного из значений (double), а затем сравнивает результирующие значения double. Вот почему вы видите разницу в поведении.

1 голос
/ 13 мая 2009

Мой ответ на другой вопрос обеспечивает реализацию Rotor. Фактический код реализован в CLR как собственный код.

В частности:

// Compare the contents (size - vtable - sink block index).
BOOL ret = memcmp(
    (void *) (pThisRef+1), 
    (void *) (pCompareRef+1), 
    pThisRef->GetMethodTable()->GetBaseSize() - sizeof(Object) - sizeof(int)) == 0;
1 голос
/ 13 мая 2009

Я предполагаю, что вы ищете ValueType.Equals (объект obj) , который наследуется вашим структурам. Он использует отражение для сравнения всех полей.

...