Condividi tramite


Overload String.Trim*(params ReadOnlySpan<char>) rimossi

Nell'ecosistema ReadOnlySpan<char> .NET può rappresentare:

  • Sequenza specifica di caratteri, spesso come sezione di un'istanza più grande System.String .
  • Raccolta di singoli caratteri, spesso come sezione di un oggetto char[].

Le versioni precedenti di .NET 9 hanno aggiunto params ReadOnlySpan<T> overload ai gruppi di metodi che avevano già un params T[] overload. Anche se questo overload è stato un'aggiunta positiva per alcuni gruppi di metodi, la doppia natura di può causare confusione per un gruppo di ReadOnlySpan<char> metodi che accetta e char[] ( String nella stessa posizione) e vengono trattati in modo diverso. Ad esempio, public static string [String::]Split(string separator, StringSplitOptions options) considera la sequenza di caratteri come un separatore. Ad esempio, "[]ne]-[Tw[]".Split("]-[", StringSplitOptions.None) suddivide in new string[] { "[]ne", "Tw[]" };. D'altra parte, public static [String::]Split(char[] separator, StringSplitOptions options) considera ogni carattere in separator come separatore distinto, quindi la divisione equivalente alla matrice restituisce new string[] { "", "", "ne", "", "", "Tw", "", "" }. Di conseguenza, qualsiasi nuovo overload che accetta un ReadOnlySpan<char> oggetto deve decidere se è simile a una stringa o a una matrice. In generale, .NET è conforme al comportamento simile alla matrice.

Considerare i nuovi String overload seguenti che accettano un ReadOnlySpan<char> argomento come proposto in dotnet/runtime#77873:

public string[] Split(params ReadOnlySpan<char> separator);
public string Trim(params ReadOnlySpan<char> trimChars);
public string TrimStart(params ReadOnlySpan<char> trimChars);
public string TrimEnd(params ReadOnlySpan<char> trimChars);

Si consideri anche il metodo di estensione comunemente definito di seguito:

public static class SomeExtensions {
    public static string TrimEnd(this string target, string trimString) {
        if (target.EndsWith(trimString) {
            return target.Substring(0, target.Length - trimString.Length);
        }

        return target;
    }
}

Per i runtime .NET esistenti, questo metodo di estensione rimuove la sequenza specificata dalla fine della stringa. Tuttavia, a causa delle regole di risoluzione dell'overload di C#, "12345!!!!".TrimEnd("!!!") preferirà il nuovo TrimEnd overload rispetto al metodo di estensione esistente e cambierà il risultato da "12345!" (rimuovendo solo un set completo di tre punti esclamativi) a "12345" (rimuovendo tutti i segni esclamativi dalla fine).

Per risolvere l'interruzione, esistono due possibili percorsi: introdurre un metodo public string TrimEnd(string trimString) di istanza che rappresenta una destinazione ancora migliore o rimuovere il nuovo metodo. La prima opzione comporta rischi aggiuntivi, perché deve decidere se restituisce un'istanza della stringa di destinazione o tutte. E ci sono senza dubbio chiamanti con codice esistente che usa ogni approccio. Pertanto, la seconda opzione è stata la scelta più appropriata per questa fase del ciclo di rilascio.

I chiamanti di String.Trim che passano singoli caratteri usando la params funzionalità, ad esempio , str.Trim(';', ',', '.')non vedranno un'interruzione. Il codice passerà automaticamente dalla chiamata string.Trim(params char[]) a string.Trim(params ReadOnlySpan<char>). Quando si esegue la ricompilazione rispetto alla versione ga di .NET 9, il compilatore tornerà automaticamente all'overload char[] .

I chiamanti di String.Trim che passano in modo esplicito un ReadOnlySpan<char> oggetto (o un tipo convertibile in ReadOnlySpan<char> che non è convertibile anche in char[]) devono modificare il codice in modo da chiamare Trim correttamente dopo questa modifica.

Per quanto riguarda String.Split, a differenza di String.Trim, questo metodo ha già un overload che è preferibile a un metodo di estensione che accetta un singolo parametro stringa e l'overload appena aggiunto ReadOnlySpan<char> . Per questo motivo, il nuovo overload di String.Split è stato mantenuto.

Nota

È necessario ricompilare qualsiasi assembly compilato in .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 o .NET 9 RC2 per assicurarsi che tutte le chiamate al metodo rimosso vengano rimosse. In caso contrario, potrebbe verificarsi un MissingMethodException errore in fase di esecuzione.

Versione introdotta

.NET 9 GA

Comportamento precedente

Il codice seguente compilato in .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 e .NET 9 RC2:

private static readonly char[] s_allowedWhitespace = { ' ', '\t', '\u00A0', '\u2000' };

// Only remove the ASCII whitespace.
str = str.Trim(s_allowedWhitespace.AsSpan(0, 2));

Prima di .NET 9 Preview 6, il codice seguente ha restituito "prefixinfix". Per .NET 9 Preview 6 e .NET 9 RC2, invece ha restituito "prefixin":

internal static string TrimEnd(this string target, string suffix)
{
    if (target.EndsWith(suffix))
    {
        return target.Substring(0, target.Length - suffix.Length);
    }

    return target;
}

...
return "prefixinfixsuffix".TrimEnd("suffix");

Nuovo comportamento

Il codice seguente che usa in modo esplicito una sezione di una matrice non viene più compilato, perché non esiste alcun overload appropriato per la chiamata:

private static readonly char[] s_allowedWhitespace = { ' ', '\t', '\u00A0', '\u2000' };

// Only remove the ASCII whitespace.
str = str.Trim(s_allowedWhitespace.AsSpan(0, 2));

Il codice che include un metodo string TrimEnd(this string target, this string suffix) di estensione ha ora lo stesso comportamento in .NET 8 e versioni precedenti. Ovvero, restituisce "prefixinfix".

Tipo di modifica che causa un'interruzione

Questa modifica può influire sulla compatibilità binaria e sulla compatibilità dell'origine.

Motivo della modifica

Molti progetti hanno metodi di estensione che sperimentano modifiche comportamentali dopo la ricompilazione. L'impatto negativo di questi nuovi metodi di istanza è stato considerato superiore al vantaggio positivo.

Ricompilare tutti i progetti compilati in .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 o .NET 9 RC2. Se il progetto viene compilato senza errori, non è necessario eseguire ulteriori operazioni. Se il progetto non viene più compilato, modificare il codice. Di seguito è riportato un possibile esempio di sostituzione:

-private static ReadOnlySpan<char> s_trimChars = [ ';', ',', '.' ];
+private static readonly char[] s_trimChars = [ ';', ',', '.' ];

...

return input.Trim(s_trimChars);

API interessate

  • System.String.Trim(System.ReadOnlySpan{System.Char})
  • System.String.TrimEnd(System.ReadOnlySpan{System.Char})
  • System.String.TrimStart(System.ReadOnlySpan{System.Char})