Различия в методах сравнения строк в C # - PullRequest
249 голосов
/ 04 сентября 2008

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

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

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

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

Ответы [ 11 ]

219 голосов
/ 04 сентября 2008

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

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, в зависимости от выбора.

70 голосов
/ 04 сентября 2008

Из MSDN:

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

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

50 голосов
/ 04 февраля 2009

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

Я следую этим рекомендациям:

Точное совпадение: РЕДАКТИРОВАТЬ: Ранее я всегда использовал оператор == по принципу, что внутри 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
18 голосов
/ 04 февраля 2009

Как сказал Ed , 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;
15 голосов
/ 07 марта 2013

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


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

  • CurrentCulture
  • CurrentCultureIgnoreCase
  • InvariantCulture
  • InvariantCultureIgnoreCase
  • Порядковый
  • OrdinalIgnoreCase

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

  • Порядковый
    • Чувствительные к регистру внутренние идентификаторы
    • Идентификаторы с учетом регистра в стандартах, таких как XML и HTTP
    • Настройки безопасности с учетом регистра
  • OrdinalIgnoreCase
    • Внутренние идентификаторы без учета регистра
    • Идентификаторы без учета регистра в таких стандартах, как XML и HTTP
    • Пути к файлам (в Microsoft Windows)
    • Ключи реестра / значения
    • Переменные среды
    • Идентификаторы ресурса (например, для обработки имен)
    • Настройки безопасности без учета регистра
  • InvariantCulture или InvariantCultureIgnoreCase
    • Некоторые сохранившиеся лингвистически важные данные
    • Отображение лингвистических данных, требующих фиксированного порядка сортировки
  • CurrentCulture или CurrentCultureIgnoreCase
    • Данные, отображаемые для пользователя
    • Большая часть пользовательского ввода

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


String.CompareTo Method (String)

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

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

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

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

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

String.Compare Method

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

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

Метод строк. Эквивалент

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

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


StringComparer class

Существует также другой способ сравнения строк, особенно с целью сортировки:

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

7 голосов
/ 04 сентября 2008

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

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

5 голосов
/ 04 сентября 2008

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

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

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

2 голосов
/ 28 июня 2013

Одно БОЛЬШОЕ различие, которое следует отметить: .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");
0 голосов
/ 14 декабря 2017
  • s1.CompareTo (s2): НЕ использовать, если основной целью является определение того, эквивалентны ли две строки
  • s1 == s2: Невозможно игнорировать регистр
  • s1.Equals (s2, StringComparison): Выдает исключение NullReferenceException, если s1 равно нулю
  • String.Equals (s2, StringComparison): В процессе исключения этот статический метод представляет собой ПОБЕДИТЕЛЬ (в предположении типичного варианта использования для определения две строки эквивалентны)!
0 голосов
/ 25 марта 2010

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

Кстати, это будет оцениваться как ложное

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

return a==b

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

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

b = "MYSTRING";

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

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

будет правдой

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

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

...