Як String.Equals (a, b) не створює StackOverflowException?


159

Оглядаючи String ==оператора, я помітив, що він дзвонить String.Equals(string a, string b), це означає, що це просто прохід.

Досліджуючи String.Equals(string a, string b)метод, я бачу, що він перевіряє рівність за допомогою ==оператора. Як це насправді працює і не викликає, StackOverflowExceptionколи роблять щось на кшталт "x" == "x"або "x" == "y"?

Оновлення : Я повідомив JetBrains про це, і вони зробили це критичним пріоритетом для dotPeek. https://youtrack.jetbrains.com/issue/DOTP-6789

Я також додав випуск щодо репортажу GitHub ILSpy.

Рівна рівність


Безкоштовний .NET Reflector (v6) відображає його "неправильно" у C # (тобто він просто показує a == b), але правильний у VB.NET : a Is b.
Марк Херд

Відповіді:


217

Ваш декомпілятор має помилку. Реальний код не перевіряє a == b, він перевіряє (Object)a == (Object)b, минаючи перевантажений оператор.


4
@Aravol правда, але джерело було нещодавно випущене
Дастін Девіс

2
Але в будь-якому випадку це досить заплутаний код. Просте object.ReferenceEquals(a,b)було б набагато зрозуміліше ..
Voo

1
@Voo Я б заперечував, що поточна версія зрозуміліша. Вам не потрібно нічого знати про object.ReferenceEqualsверсію для передачі (наприклад, що, якщо aце null?), І, поки ви знаєте, що таке кастинг, це, звичайно, не заплутано.
wchargin

72
"Ваш декомпілятор має помилку". Скидає мікрофон.
espinchi

1
@Voo Моя здогадка: MS вважають (Object)a == (Object)bі Object.ReferenceEquals(a, b)приблизно однаково читабельною, але це не здивувало б мене, якщо Object.ReferenceEquals(a, b)просто є невеликий шанс не потрапляти в ряд, якщо буде досягнута максимальна глибина введення. MS робить безліч мікрооптимізацій, оскільки більшість щільних циклів у коді користувача в кінцевому підсумку викликає MS-код.

50

Ось справжній код від Microsoft. Оператор ==буде реалізували сек

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

==виклики оператора, String.Equals який реалізується як:

public static bool Equals(String a, String b) {
    if ((Object)a==(Object)b) {
        return true;
    }

    if ((Object)a==null || (Object)b==null) {
        return false;
    }

    if (a.Length != b.Length)
        return false;

    return EqualsHelper(a, b);
}

Як бачите, порівняння для рівності рядків робиться за допомогою if ((Object)a==(Object)b)кастингу рядка objectі потім порівняння. Таким чином, це не буде викликати перевантажений оператор ==у рядковому класі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.