Як 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.