Оператор равенства строк = С#

Я попытался заглянуть в код, реализованный для оператора сравнения в строчном классе в С#. Что было найдено:

//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);
}

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

static Equals(object o1, object o2)

в классе Object, который должен быть частью класса String?

Ответ 1

Операторы равенства в С# не являются полиморфными. Когда вы оцениваете 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 содержит как метод static bool Equals(string a, string b), так и метод static bool Equals(object a, object b). Разница в том, что первая определена в самом классе string, в то время как последняя наследуется от класса object (который является базовым классом string). Ваш отражатель может отображать или не отображать унаследованные методы на основе его настроек.

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

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

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

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

ldc.i4.1
ret

bne.un.s определяется как" Ветвь к целевой команде с указанным смещением, если два значения беззнакового целого не равны (значения без знака), короткая форма.

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

Ответ 2

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

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

Ответ 3

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

public static bool Equals(MyClass a, MyClass b) 
{ 
    return ReferenceEquals(a, b)
        || ((!ReferenceEquals(a, null) && !ReferenceEquals(b, null)) && a.Equals(b))); 
} 

Ответ 4

Метод равенства, на который он ссылается, таков:

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, который принимает две строки, а не два объекта.