2013-07-21 26 views
17

Ho la seguente metodo nel mio codice C#:Come è possibile in questo codice: "ArgumentOutOfRangeException: startIndex non può essere maggiore della lunghezza della stringa"?

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

L'applicazione sembra molto semplice ed evidente, ed ha una copertura eccellente per unit test. Non si sono mai verificati risultati imprevisti sulla mia macchina, sui server di build o su altre macchine a cui ho accesso o nella maggior parte degli ambienti di produzione.

Se non fosse che un solo cliente a distanza riporta di tanto in tanto l'arresto di un'applicazione a questo metodo con la seguente analisi dello stack:

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 ... 

Purtroppo, non ho un accesso remoto a questo ambiente di produzione o ai suoi dati, o a qualsiasi informazione aggiuntiva. Per alcuni motivi, al momento non riesco a distribuire il sistema di registrazione o la raccolta di dump degli arresti anomali.

Guardando il codice e provando diverse combinazioni di argomenti, non riesco a immaginare come possa verificarsi questa eccezione.

Potresti per favore aiutarmi con alcune idee?

+0

IndexOf è specifico per la cultura. Dai uno sguardo agli esempi [qui] (http://msdn.microsoft.com/en-us/library/ms224425.aspx) per vedere come può cambiare l'indice. –

+0

È preferibile utilizzare il metodo String.Remove (Int32, Int32). Potresti trovarlo più indulgente. ': @ string.Remove (index, substring.Length)' – tinstaafl

risposta

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

Molte funzioni per stringhe manipolazione NET, tra IndexOf sono cultura -specifico per impostazione predefinita (in genere sono presenti sovraccarichi in cui è possibile passare StringComparison.Ordinal o StringComparer.Ordinal per passare a confronti bit a bit). Personalmente, non sono molto contento di quello che è stato scelto come comportamento predefinito, ma è troppo tardi per fare qualcosa al riguardo, tranne forse, impostando linee guida di sviluppo esplicite e regole FxCop.

Ma a volte le operazioni specifiche della cultura sono esattamente ciò di cui hai bisogno. Sfortunatamente, la loro semantica può essere complicata e contro-intuitiva, può violare alcuni invarianti normalmente presupposti e avere un sacco di casi d'angolo di cui occuparsi. Gli sviluppatori che sono incaricati di implementare una logica sensibile alla cultura in un'applicazione dovrebbero essere molto qualificati in questo settore e capire sempre esattamente cosa stanno facendo. Consiglierei di impostare standard di revisione e test per questa area al di sopra del normale.

+0

Si potrebbe aggiungere che può aggiustarlo aggiungendo 'StringComparison.Ordinal' a 'IndexOf'. –

+1

Dalla documentazione: http://msdn.microsoft.com/en-us/library/k8b1470s.aspx I set di caratteri includono caratteri ignorabili, ovvero caratteri che non vengono considerati durante l'esecuzione di un confronto linguistico o sensibile alla cultura.In una ricerca sensibile alla cultura, se il valore contiene un carattere ignorabile, il risultato è equivalente alla ricerca con quel carattere rimosso. ... –

-1

Dopo i commenti, ho scoperto che la sottostringa non ha esito negativo sull'indice non valido. Il vero problema è con

@string.IndexOf(substring); 

come sottolinea Pierre-Luc Pineault

Correzione:

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

ABCDEF e EF restituiscono correttamente ABCD. Hai provato a eseguire il codice? –

+0

Hai ragione. Ho appena testato il codice e ho notato che la sottostringa è indulgente in tale scenario. –

Problemi correlati