Различия в методах сравнения строк в C #

Сравнить строку в C # довольно просто. На самом деле есть несколько способов сделать это. Я перечислил некоторые из них в блоке ниже. Что мне любопытно, так это различия между ними и когда один должен использоваться вместо другого? Следует ли избегать любой ценой? Есть еще что-то, чего я не перечислил?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(Примечание: в этом примере я ищу равенство, не меньше или больше, но не стесняйтесь комментировать и это)


person Craig    schedule 04.09.2008    source источник
comment
Одна ловушка заключается в том, что вы не можете использовать stringValue.Equals (null), поскольку предполагает, что вы можете вызвать метод на null   -  person johnc    schedule 08.01.2009
comment
Справочник MSDN   -  person Robert Harvey    schedule 06.05.2014
comment
@RobertHarvey Причина, по которой я пришел к stackoverflow, в том, что мне не нужно читать несколько страниц для ответов.   -  person Syaiful Nizam Yahya    schedule 12.12.2019
comment
@Syaiful: Я пришел в Stack Overflow, чтобы найти ответы, которых нет в документации.   -  person Robert Harvey    schedule 12.12.2019


Ответы (11)


Вот правила работы этих функций:

stringValue.CompareTo(otherStringValue)

  1. null стоит перед строкой
  2. он использует CultureInfo.CurrentCulture.CompareInfo.Compare, что означает, что будет использоваться сравнение, зависящее от языка и региональных параметров. Это может означать, что ß будет сравниваться с SS в Германии или аналогичным

stringValue.Equals(otherStringValue)

  1. null не считается ни с чем
  2. если вы не укажете параметр StringComparison, он будет использовать то, что выглядит как прямая порядковая проверка равенства, т.е. ß не то же самое, что SS, на любом языке или культуре

stringValue == otherStringValue

  1. Не то же самое, что stringValue.Equals().
  2. Оператор == вызывает статический метод Equals(string a, string b) (который, в свою очередь, переходит к внутреннему EqualsHelper для сравнения.
  3. Вызов .Equals() в строке null вызывает исключение ссылки null, а вызов == - нет.

Object.ReferenceEquals(stringValue, otherStringValue)

Просто проверяет, совпадают ли ссылки, т.е. это не просто две строки с одинаковым содержимым, вы сравниваете строковый объект сам с собой.


Обратите внимание, что с параметрами выше, которые используют вызовы методов, есть перегрузки с дополнительными параметрами, чтобы указать, как сравнивать.

Мой совет, если вы просто хотите проверить равенство, - решить, хотите ли вы использовать сравнение, зависящее от культуры или нет, а затем использовать .CompareTo или .Equals, в зависимости от выбора.

person Lasse V. Karlsen    schedule 04.09.2008
comment
stringValue.Equals (otherStringValue): null не равно null Lol, я бы сказал, что нет. null равно исключению ObjectReferenceNotSet. - person Kevin; 05.02.2009
comment
== - это не то же самое, что .Equals () ... Оператор == вызывает статический метод Equals (строка a, строка b) (который, в свою очередь, переходит к внутреннему EqualsHelper для выполнения сравнения. Вызов .Equals по нулю string получает нулевую ссылку, исключая, а on == - нет. - person Dan C.; 05.02.2009
comment
С другой стороны, .Equals немного быстрее (на один внутренний вызов метода меньше), но менее читабелен - возможно, конечно :). - person Dan C.; 05.02.2009
comment
Я думал, что '==' будет выполнять сравнения ссылок, а object.equals - сравнения значений. Как '==' и string.equals работают одинаково? - person amesh; 09.08.2012
comment
в ответе следует указать разницу ==, это довольно большая разница. - person Joe Cartano; 30.10.2013
comment
не могли бы вы добавить к каждому из них регистр? - person serge; 28.05.2021

Из MSDN:

"Метод CompareTo был разработан в первую очередь для использования в операциях сортировки или сортировки по алфавиту. Его не следует использовать, когда основной целью вызова метода является определение эквивалентности двух строк. Чтобы определить, эквивалентны ли две строки, вызовите метод Equals. "

Они предлагают использовать .Equals вместо .CompareTo, когда стремятся исключительно к равенству. Я не уверен, есть ли разница между .Equals и == для класса string. Иногда я буду использовать .Equals или Object.ReferenceEquals вместо == для моих собственных классов на случай, если кто-то придет позже и переопределит оператор == для этого класса.

person Ed S.    schedule 04.09.2008
comment
С тобой такое когда-нибудь случалось? (Переопределение ==) ... Я считаю, что это слишком защитное программирование =) - person juan; 05.02.2009
comment
Да, именно поэтому я теперь использую Object.ReferenceEquals, когда ищу равенство объектов :). Это может показаться чересчур оборонительным, но я не маниакальный по этому поводу, и, честно говоря, такая ситуация возникает не очень часто. - person Ed S.; 05.02.2009
comment
Я сомневаюсь, что это «защитное кодирование» полезно. Что, если владелец класса должен переопределить оператор ==, а затем обнаружит, что никто его не использует? - person Dave Van den Eynde; 27.02.2012
comment
@DaveVandenEynde: Да ... Я написал это некоторое время назад. Я не делаю это регулярно, только заменяю .Equals, когда это необходимо. - person Ed S.; 27.02.2012
comment
Этот ответ не отвечает на вопрос. - person sisharp; 03.06.2013

Если вам когда-нибудь интересно узнать о различиях в методах BCL, Reflector - ваш друг :-)

Я следую этим правилам:

Точное совпадение: EDIT: раньше я всегда использовал оператор == по тому принципу, что внутри Equals (строка, строка) оператор object == используется для сравнения ссылок на объекты, но это похоже на strA. Equals (strB) по-прежнему на 1-11% быстрее, чем string.Equals (strA, strB), strA == strB и string.CompareOrdinal (strA, strB). Я тестировал цикл с помощью StopWatch как на интернированных, так и на не интернированных строковых значениях, с одинаковой / разной длиной строки и разными размерами (от 1 Б до 5 МБ).

strA.Equals(strB)

Удобочитаемое соответствие (западные культуры, без учета регистра):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

Удобочитаемое соответствие (все другие культуры, нечувствительность к регистру / акценту / кана и т. д., определенные CultureInfo):

string.Compare(strA, strB, myCultureInfo) == 0

Удобочитаемое соответствие особым правилам (для всех других культур):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0
person max    schedule 04.02.2009

Как сказал Эд, CompareTo используется для сортировки.

Однако есть разница между .Equals и ==.

== преобразуется в по существу следующий код:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

Простая причина в том, что следующее вызовет исключение:

string a = null;
string b = "foo";

bool equal = a.Equals(b);

И следующего не будет:

string a = null;
string b = "foo";

bool equal = a == b;
person Jonathan C Dickinson    schedule 04.02.2009
comment
как насчет чувствительности к регистру? - person serge; 28.05.2021
comment
и заметьте, что вы можете использовать string.Equals(a, b) - person serge; 28.05.2021

Хорошее объяснение и методы решения проблем сравнения строк можно найти в статье Новые рекомендации по использованию строк в Microsoft .NET 2.0, а также в Рекомендации по использованию строк в .NET Framework.


Каждый из упомянутых методов (и других) преследует определенную цель. Ключевое различие между ними заключается в том, какого типа StringComparison Enumeration они есть. использование по умолчанию. Есть несколько вариантов:

  • CurrentCulture
  • CurrentCultureIgnoreCase
  • ИнвариантКультура
  • InvariantCultureIgnoreCase
  • Порядковый
  • OrdinalIgnoreCase

Каждый из приведенных выше типов сравнения нацелен на разные варианты использования:

  • Ordinal
    • Case-sensitive internal identifiers
    • Идентификаторы с учетом регистра в таких стандартах, как XML и HTTP.
    • Настройки безопасности с учетом регистра
  • OrdinalIgnoreCase
    • Case-insensitive internal identifiers
    • Идентификаторы без учета регистра в таких стандартах, как XML и HTTP
    • Пути к файлам (в Microsoft Windows)
    • Ключи / значения реестра
    • Переменные среды
    • Идентификаторы ресурсов (например, имена дескрипторов)
    • Настройки безопасности без учета регистра
  • InvariantCulture or InvariantCultureIgnoreCase
    • Some persisted linguistically-relevant data
    • Отображение лингвистических данных, требующих фиксированного порядка сортировки
  • CurrentCulture or CurrentCultureIgnoreCase
    • Data displayed to the user
    • Большая часть пользовательского ввода

Обратите внимание, что StringComparison Enumeration, а также перегрузки для методов сравнения строк существует с .NET 2.0.


Метод String.CompareTo (String)

Фактически является типобезопасной реализацией метода IComparable.CompareTo. Интерпретация по умолчанию: CurrentCulture.

Использование:

Метод CompareTo был разработан в первую очередь для использования в операциях сортировки или сортировки по алфавиту.

Таким образом

Реализация интерфейса IComparable обязательно будет использовать этот метод

String.Compare Method

Статический член String Class, который имеет много перегрузок. Интерпретация по умолчанию: CurrentCulture.

По возможности следует вызывать перегрузку метода Compare, который включает параметр StringComparison.

Метод String.Equals

Переопределено из класса Object и перегружено для обеспечения безопасности типов. Интерпретация по умолчанию: Порядковый номер. Заметь:

Методы равенства класса String включают статический Equals, статический оператор == и метод экземпляра Equals.


класс StringComparer

Есть также другой способ справиться со сравнением строк, особенно нацеленный на сортировку:

Вы можете использовать класс StringComparer для создания сравнения по конкретному типу для сортировки элементов в общей коллекции. Такие классы, как Hashtable, Dictionary, SortedList и SortedList, используют класс StringComparer для целей сортировки.

person Ryszard Dżegan    schedule 07.03.2013
comment
Согласно некоторым другим сообщениям на SO, все методы, кроме порядковых, имеют случаи, когда Compare (a, b) и Compare (b, a) могут возвращать 1, и ошибка была классифицирована как не будет исправлена. Таким образом, я не уверен, что такие сравнения имеют какой-либо вариант использования. - person supercat; 04.03.2014
comment
@supercat вы можете дать ссылку или привести пример? - person Noctis; 04.11.2014
comment
См. stackoverflow.com/questions/17599084/ для обсуждения проблемы. - person supercat; 04.11.2014

Не то, чтобы производительность обычно имела значение в 99% случаев, когда вам нужно это делать, но если вам приходилось делать это в цикле несколько миллионов раз, я настоятельно рекомендую вам использовать .Equals или ==, потому что, как только он найдет символ который не совпадает, выдает все это как false, но если вы используете CompareTo, ему придется выяснить, какой символ меньше другого, что приведет к немного худшему времени производительности.

Если ваше приложение будет работать в разных странах, я бы порекомендовал вам взглянуть на последствия CultureInfo и, возможно, использовать .Equals. Поскольку я действительно пишу приложения только для США (и мне все равно, что кто-то не работает должным образом), я всегда просто использую ==.

person viggity    schedule 04.09.2008

В перечисленных вами формах нет большой разницы между ними. CompareTo заканчивает тем, что вызывает CompareInfo метод, который выполняет сравнение с использованием текущего языка и региональных параметров; Equals вызывается оператором ==.

Если принять во внимание перегрузки, все изменится. Compare и == могут использовать только текущий язык и региональные параметры для сравнения строки. Equals и String.Compare могут принимать StringComparison аргумент перечисления, позволяющий указывать сравнения без учета языка и региональных параметров или без учета регистра. Только String.Compare позволяет указывать CultureInfo и выполнять сравнения с использованием языка и региональных параметров, отличных от культуры по умолчанию.

Из-за его универсальности я использую String.Compare больше, чем любой другой метод сравнения; это позволяет мне точно указать, что я хочу.

person OwenP    schedule 04.09.2008

Следует отметить одно БОЛЬШОЕ отличие: .Equals () вызовет исключение, если первая строка равна нулю, тогда как == не будет.

       string s = null;
        string a = "a";
        //Throws {"Object reference not set to an instance of an object."}
        if (s.Equals(a))
            Console.WriteLine("s is equal to a");
        //no Exception
        if(s==a)
            Console.WriteLine("s is equal to a");
person Rauld    schedule 28.06.2013

  • s1.CompareTo (s2): НЕ используйте, если основная цель - определить, эквивалентны ли две строки
  • s1 == s2: нельзя игнорировать регистр
  • s1.Equals (s2, StringComparison): выдает исключение NullReferenceException, если s1 имеет значение null
  • String.Equals (s2, StringComparison): в процессе исключения этот статический метод является ПОБЕДИТЕЛЕМ (при типичном варианте использования, чтобы определить, две строки эквивалентны)!
person John DiFini    schedule 14.12.2017

Использование .Equals также намного проще читать.

person hometoast    schedule 04.09.2008

с .Equals вы также получаете параметры StringComparison. очень удобен для игнорирования дела и прочего.

кстати, это будет ложно

string a = "myString";
string b = "myString";

return a==b

Поскольку == сравнивает значения a и b (которые являются указателями), это будет оцениваться как истинное, только если указатели указывают на один и тот же объект в памяти. .Equals разыменовывает указатели и сравнивает значения, хранящиеся в указателях. Здесь a.quals (b) будет истинным.

и если вы измените b на:

b = "MYSTRING";

тогда a.Equals (b) ложно, но

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

было бы правдой

a.CompareTo (b) вызывает функцию CompareTo строки, которая сравнивает значения в указателях и возвращает ‹0, если значение, хранящееся в a, меньше значения, хранящегося в b, возвращает 0, если a.Equals (b) истинно, и > 0 в противном случае. Тем не менее, это чувствительно к регистру, я думаю, что у CompareTo есть варианты игнорировать регистр и тому подобное, но сейчас нет времени смотреть. Как уже заявляли другие, это будет сделано для сортировки. Такое сравнение на равенство приведет к ненужным накладным расходам.

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

person David    schedule 25.03.2010
comment
Часть a == b неверна. Оператор == эффективно перегружен для класса String и сравнивает значения независимо от фактических ссылок. - person Goyuix; 02.04.2010