Строковый оператор равенства == в c # - PullRequest
3 голосов
/ 16 февраля 2012

Я попытался заглянуть в код, реализованный для оператора сравнения в строковом классе в C #.Было найдено следующее:

//THIS IS NOT WHAT I MEANT
public static bool Equals(object objA, object objB)
{
    return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
}

//THIS IS WHAT I SEE REALLY and the above is what I would expect to see
public static bool Equals(string a, string b)
{
    return ((a == b) || (((a != null) && (b != null)) && EqualsHelper(a, b)));
}



public static bool operator ==(string a, string b)
{
    return Equals(a, b);
}

Я не знаю, обманывает ли меня Рефлектор, но когда я попытался реализовать эту стратегию для своего класса, я получил бесконечный циклРавен и перегруженный оператор == (как и ожидалось).Есть ли что-то другое в строковом классе или мой рефлектор сообщает, что метод

static Equals(object o1, object o2)

класса Object является частью класса String?

Ответы [ 4 ]

7 голосов
/ 16 февраля 2012

Нет метода String.Equals(object, object).
Вы видите Object.Equals.

Причина, по которой он не повторяется, заключается в том, что objA == objB вызывает встроенный оператор равенства объектов, а не пользовательский оператор равенства строк. (Операторские перегрузки разрешаются на основе типа операндов время компиляции )

6 голосов
/ 16 февраля 2012

Операторы равенства в C # не являются полиморфными. Когда вы оцениваете objA == objB, вы фактически выполняете реализацию оператора ==(object a, object b) (которая проверяет равенство ссылок), а не ==(string a, string b), поскольку объявленный тип переменных objA и objB равен object, не string.

Ошибка, которую вы, вероятно, делаете в своем коде, заключается в том, что вы не приводите экземпляры своего класса к object до оценки оператора == на них.

Предположим, у вас есть:

public static bool Equals(MyClass objA, MyClass objB)
{
    return objA == objB || objA != null && objB != null && objA.Equals(objB);
}

… вам нужно заменить его на:

public static bool Equals(MyClass objA, MyClass objB)
{
    return (object)objA == (object)objB || objA != null && objB != null && objA.Equals(objB);
}

… что эквивалентно:

public static bool Equals(MyClass objA, MyClass objB)
{
    return object.ReferenceEquals(objA, objB) || objA != null && objB != null && objA.Equals(objB);
}

Обновление : класс String содержит оба a static bool Equals(string a, string b) метод и a static bool Equals(object a, object b) метод. Разница в том, что первый определяется внутри самого класса String, а последний наследуется от класса Object (который является базовым классом String). Ваш отражатель может отображать или не отображать унаследованные методы в зависимости от его настроек.

В опубликованном вами коде, поскольку объявленный тип objA и objB равен object, будет вызван оператор с параметрами object, независимо от фактического типа экземпляров.

Обновление 2 : ваш обновленный код содержит бесконечную рекурсию. Я предполагаю, что это может быть ошибка в инструменте отражателя.

Обновление 3 : Это похоже на ошибку в дизассемблере. Первое условие в реализации оператора Equals(string a, string b) показано в разобранном коде C # как a == b. Тем не менее, первые несколько строк кода IL на самом деле:

ldarg.0
ldarg.1
bne.un.s IL_0006

ldc.i4.1
ret

bne.un.s определяется как «Переход к целевой инструкции с указанным смещением, если два целых значения без знака не равны (значения без знака), краткая форма».

Таким образом, похоже, что эталонное равенство выполняется в конце концов.

1 голос
/ 16 февраля 2012

Менее запутанное решение: не используйте оператор ==:

public static bool Equals(MyClass a, MyClass b) 
{ 
    return ReferenceEquals(a, b)
        || ((!ReferenceEquals(a, null) && !ReferenceEquals(b, null)) && a.Equals(b))); 
} 
0 голосов
/ 16 февраля 2012

Метод equals, к которому он относится, таков:

public static bool Equals(string a, string b)
{
    /* == is the object equals- not the string equals */
    return a == b || (a != null && b != null && string.EqualsHelper(a, b));
}

public static bool operator ==(string a, string b)
{
    return string.Equals(a, b);
}

т.е. метод equals, который принимает две строки, а не два объекта.

...