51

Я читаю зашифрованные учетные данные/строки подключения из файла конфигурации. Resharper говорит мне, "String.IndexOf (строка) является культура конкретной здесь" на этой линии:Могут ли строки сравнения действительно отличаться в зависимости от культуры, когда строка гарантированно не изменится?

if (line.Contains("host=")) { 
    _host = line.Substring(line.IndexOf(
     "host=") + "host=".Length, line.Length - "host=".Length); 

... и так хочет изменить его на:

if (line.Contains("host=")) { 
    _host = line.Substring(line.IndexOf("host=", System.StringComparison.Ordinal) + "host=".Length, line.Length - "host=".Length); 

Значение I» m чтение всегда будет «host =» независимо от того, где приложение может быть развернуто. Действительно ли разумно добавить этот бит System.StringComparison.Ordinal?

Что еще более важно, может ли это повредить что-либо (использовать его)?

ответ

59

Абсолютно. За MSDN (http://msdn.microsoft.com/en-us/library/d93tkzah.aspx),

Этот метод выполняет слово (чувствительны к регистру и культуры чувствительных) поиска с использованием текущей культуры.

Таким образом, вы можете получить разные результаты, если вы запускаете его под другой культурой (с помощью региональных и языковых настроек на панели управления).

В этом конкретном случае у вас, вероятно, не будет проблемы, но в строке поиска введите i и запустите его в Турции, и это, вероятно, испортит вам день.

См MSDN: http://msdn.microsoft.com/en-us/library/ms973919.aspx

Эти новые рекомендации и API, существуют, чтобы облегчить заблудших предположения о поведении строки по умолчанию API. Канонический пример ошибок, возникающих там, где нелингвистические строковые данные интерпретируется лингвистически, является проблемой «Турецкий-I».

Для почти всех латинских алфавитов, в том числе английского языка, символ i (\ u0069) является строчной версией символа I (\ u0049). Это правило быстро становится стандартным для программиста в такой культуре. Однако на турецком языке («tr-TR») существует капитал «i с точкой», символ (\ u0130), который является капитальной версией i. Точно так же на турецком языке существует строчная «i без точки» или (\ u0131), которая капитализируется на I. Это происходит в культуре Azeri («az»).

Таким образом, предположения, обычно сделанные об заглавном листе i или нижнем корпусе, я недопустим среди всех культур. Если используются перегрузки по умолчанию для процедур сравнения строк, они будут с учетом различий между культурами. Для не лингвистических данных, как и в в следующем примере, это может привести к нежелательным результатам:

Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US") 
Console.WriteLine("Culture = {0}", 
    Thread.CurrentThread.CurrentCulture.DisplayName); 
Console.WriteLine("(file == FILE) = {0}", 
    (String.Compare("file", "FILE", true) == 0)); 

Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR"); 
Console.WriteLine("Culture = {0}", 
    Thread.CurrentThread.CurrentCulture.DisplayName); 
Console.WriteLine("(file == FILE) = {0}", 
    (String.Compare("file", "FILE", true) == 0)); 

Из-за разницы в сравнении I, результаты сравнений изменяются, когда нить культура изменяется. Это выход:

Culture = English (United States) 
(file == FILE) = True 
Culture = Turkish (Turkey) 
(file == FILE) = False 

Ниже приведен пример без случая:

var s1 = "é"; //é as one character (ALT+0233) 
var s2 = "é"; //'e', plus combining acute accent U+301 (two characters) 

Console.WriteLine(s1.IndexOf(s2, StringComparison.Ordinal)); //-1 
Console.WriteLine(s1.IndexOf(s2, StringComparison.InvariantCulture)); //0 
Console.WriteLine(s1.IndexOf(s2, StringComparison.CurrentCulture)); //0 
+8

+1 для показа примера (Турецкий). –

+2

Почему IndexOf имеет какое-либо отношение к делу, microsoft смешивает все в обычном раздутом пути, который им нравится. Их ошибка состоит в том, чтобы всегда предполагать наиболее сложную первую здесь, и позвольте нам выбрать путь низкого уровня с чрезвычайно подробным способом. –

+4

Хорошо, забудьте о случае. Существуют и другие примеры, если вы выходите за пределы английского. Например, e + сочетание акцента, против é. Они различаются по порядковым, но тем же лингвистически (см. Править). Угадайте, язык жесткий. –

25

CA1309: UseOrdinalStringComparison

Это не больно не использовать его, но "явно установив параметр либо в StringComparison.Ordinal или StringComparison.OrdinalIgnoreCase, код часто набирает скорость, повышает правильность и становится более надежным. ".


Что такое Ординал и почему это имеет значение для вашего дела?

Операция, которая использует порядковые правила сортировки выполняет сравнение на основе на числовое значение (точка кода Unicode) каждого Char в строке. Сравнение ординалов происходит быстро, но нечувствительно к культуре. Когда вы используете правила сортировки для сортировки строк, начинающихся с символов Unicode (U +), строка U + xxxx идет перед строкой U + yyyy, если значение xxxx численно меньше yyyy.

И, как вы заявили ... строковое значение, которое вы читаете, не чувствительно к культуре, поэтому имеет смысл использовать сравнение ординалов, а не сравнение слов. Просто помните, Ординал означает «это не чувствительность к культуре».

5

Чтобы ответить на ваш конкретный вопрос: Нет, но инструмент статического анализа не сможет понять, что ваше входное значение никогда не будет содержать информацию о локали.

Смежные вопросы