2013-07-21 22 views
17

は、私は私のC#コードで、次の方法があります。どのようにこのコードで可能です: "ArgumentOutOfRangeException:startIndexは文字列の長さを超えることはできません"?

/// <summary> 
/// Removes the first (leftmost) occurence of a <paramref name="substring"/> from a <paramref name="string"/>. 
/// </summary> 
/// <param name="string">The string to remove the <paramref name="substring"/> from. Cannot be <c>null</c>.</param> 
/// <param name="substring">The substring to look for and remove from the <paramref name="string"/>. Cannot be <c>null</c>.</param> 
/// <returns> 
/// The rest of the <paramref name="string"/>, after the first (leftmost) occurence of the <paramref name="substring"/> in it (if any) has been removed. 
/// </returns> 
/// <remarks> 
/// <list type="bullet"> 
/// <item>If the <paramref name="substring"/> does not occur within the <paramref name="string"/>, the <paramref name="string"/> is returned intact.</item> 
/// <item>If the <paramref name="substring"/> has exactly one occurence within the <paramref name="string"/>, that occurence is removed, and the rest of the <paramref name="string"/> is returned.</item> 
/// <item>If the <paramref name="substring"/> has several occurences within the <paramref name="substring"/>, the first (leftmost) occurence is removed, and the rest of the <paramref name="string"/> is returned.</item> 
/// </list> 
/// </remarks> 
/// <exception cref="ArgumentNullException"> 
/// The <paramref name="string"/> is <c>null</c>. -or- The <paramref name="substring"/> is <c>null</c>. 
/// </exception> 
public static string RemoveSubstring(string @string, string substring) 
{ 
    if (@string == null) 
     throw new ArgumentNullException("string"); 

    if (substring == null) 
     throw new ArgumentNullException("substring"); 

    var index = @string.IndexOf(substring); 
    return index == -1 
     ? @string 
     : @string.Substring(0, index) + @string.Substring(index + substring.Length); 
} 

実装は非常にシンプルかつ明白に見え、ユニットテストで優れたカバレッジを持っています。マシン、ビルドサーバー、またはアクセス権を持つ他のマシンや、ほとんどの実稼働環境で予期しない結果が発生したことはありません。

一つだけのリモート顧客は時折、次のスタックトレースで、この方法でアプリケーションのクラッシュを報告することを除い:残念ながら

System.ArgumentOutOfRangeException: startIndex cannot be larger than length of string. 
Parameter name: startIndex 
    at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy) 
    at System.String.Substring(Int32 startIndex) 
    at MyNamespace.StringUtils.RemoveSubstring(String string, String substring) 
    at ... 

、私はこの本番環境へまたはそのデータへのリモートアクセスを持っていない、または追加情報に何らかの理由で、現在私はそこにロギングシステムやクラッシュダンプの収集を展開することができません。

コードを見て、さまざまな引数の組み合わせを試してみると、この例外がどのように起こる可能性があるのか​​想像できません。

いくつかのアイデアを私に教えてください。

+0

IndexOfは培養特異的である。インデックスの変更方法については、examples [here](http://msdn.microsoft.com/en-us/library/ms224425.aspx)を参照してください。 –

+0

String.Remove(Int32、Int32)メソッドを使用する方がよい場合があります。より寛容に思えるかもしれません。 ':@ string.Remove(index、substring.Length)' – tinstaafl

答えて

10
RemoveSubstring("A", "A\uFFFD"); // throws ArgumentOutOfRangeException 
RemoveSubstring("A", "A\u0640"); // throws ArgumentOutOfRangeException 

多くの関数は、文化です:ピエール・リュックPineaultによって

修正を指摘したように本当の問題は

@string.IndexOf(substring); 

でありますデフォルトでは(通常、ビット比較の切り替えにはStringComparison.OrdinalまたはStringComparer.Ordinalを渡すことができるオーバーロードがあります)。個人的には、デフォルトの動作に選ばれたものには満足していませんが、明示的な開発ガイドラインやFxCopルールを設定することを除いて、何もするのは遅すぎます。

しかし、文化固有の操作は、必要なものだけです。残念なことに、それらのセマンティクスは扱いにくく、直感的であり、通常仮定されている不変量に違反する可能性があり、処理するコーナーケースがたくさんあります。アプリケーションで文化に敏感なロジックを実装することを担当する開発者は、この分野で非常に適格であり、常に自分が行っていることを正確に理解する必要があります。私はこの領域のレビューとテストの基準を通常以上に設定することをお勧めします。

+0

'IndexOf'に' StringComparison.Ordinal'を追加することで修正できます。 –

+1

ドキュメントから:http://msdn.microsoft.com/en-us/library/k8b1470s.aspx 文字セットには、無視できる文字が含まれています。文字は、言語的または文化に敏感な比較を実行する際に考慮されません。文化に敏感な検索では、valueに無視可能な文字が含まれている場合、その文字を削除して検索するのと同じ結果になります。 ... –

-1

コメントの後、部分文字列が無効なインデックスで失敗しないことがわかりました。 IndexOfを含む.NETの文字列操作のための

@string.IndexOf(substring, StringComparison.Ordinal); 
+4

ABCDEFとEFはABCDを正しく返します。コードを実行しようとしましたか? –

+0

あなたは正しいです。私はちょうどコードをテストし、そのようなシナリオで部分文字列が許されていることに気付きました。 –

関連する問題