54

構成ファイルから暗号化された資格情報/接続文字列を読み取っています。Resharper は、次の行で「String.IndexOf(string) はここではカルチャ固有です」と教えてくれます。

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);

私が読んでいる値は、アプリが展開されている場所に関係なく、常に「host =」です。この「System.StringComparison.Ordinal」ビットを追加するのは本当に賢明ですか?

さらに重要なことは、(それを使用することで) 何かを害する可能性はありますか?

4

3 に答える 3

66

絶対。MSDN(http://msdn.microsoft.com/en-us/library/d93tkzah.aspx)ごとに、

このメソッドは、現在のカルチャを使用して単語(大文字と小文字を区別し、カルチャを区別する)検索を実行します。

そのため、異なるカルチャで実行すると(コントロールパネルの地域と言語の設定を介して)、異なる結果が得られる可能性があります。

この特定のケースでは、おそらく問題はありませんがi、検索文字列を挿入してトルコで実行すると、おそらく1日が台無しになります。

MSDNを参照してください:http://msdn.microsoft.com/en-us/library/ms973919.aspx

これらの新しい推奨事項とAPIは、デフォルトの文字列APIの動作に関する誤った仮定を軽減するために存在します。非言語文字列データが言語的に解釈される場合に発生するバグの標準的な例は、「トルコ語-I」問題です。

アメリカ英語を含むほぼすべてのラテンアルファベットでは、文字i(\ u0069)は文字I(\ u0049)の小文字バージョンです。このケーシングルールは、そのような文化でプログラミングする人にとってはすぐにデフォルトになります。ただし、トルコ語( "tr-TR")には、大文字の "i with a dot"文字(\ u0130)があります。これはiの大文字バージョンです。同様に、トルコ語では、小文字の「ドットのないi」または(\ u0131)があり、これはIを大文字にします。この動作はアゼルバイジャン文化(「az」)でも発生します。

したがって、iの大文字化または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
于 2012-06-08T00:03:36.390 に答える
27

CA1309:UseOrdinalStringComparison

これを使用しなくてもはありませんが、「パラメーターを明示的に StringComparison.Ordinal または StringComparison.OrdinalIgnoreCase に設定することで、多くの場合、コードの速度が向上し、正確さが増し、信頼性が向上します。」.


Ordinal とは正確には何ですか?なぜそれがあなたのケースにとって重要なのですか?

序数の並べ替え規則を使用する操作は、文字列内の各 Char の数値 (Unicode コード ポイント) に基づいて比較を実行します。序数比較は高速ですが、カルチャに依存しません。序数の並べ替え規則を使用して Unicode 文字 (U+) で始まる文字列を並べ替える場合、xxxx の値が数値的に yyyy よりも小さい場合、文字列 U+xxxx は文字列 U+yyyy の前になります。

そして、あなたが述べたように...あなたが読んでいる文字列値は文化に敏感ではないので、Word比較ではなく序数比較を使用することは理にかなっています. Ordinal は「これは文化に依存しない」という意味です。

于 2012-06-07T23:51:08.740 に答える
7

特定の質問に答えるには: いいえ、しかし静的分析ツールは、入力値にロケール固有の情報が含まれていないことを認識することはできません。

于 2012-06-07T23:55:10.363 に答える