Dela via


String.Trim*(params ReadOnlySpan<char>) överlagringar borttagna

I .NET-ekosystemet ReadOnlySpan<char> kan det representera:

  • En specifik sekvens med tecken, ofta som en del av en större System.String instans.
  • En samling enkla tecken, ofta som en sektor av en char[].

Tidigare versioner av .NET 9 lade till params ReadOnlySpan<T> överlagringar i metodgrupper som redan hade en params T[] överlagring. Även om den här överbelastningen var ett positivt tillägg för vissa metodgrupper kan den dubbla karaktären ReadOnlySpan<char> hos orsaka förvirring för en metodgrupp som accepterar en char[] och en String (i samma position) och de behandlas annorlunda. Till exempel public static string [String::]Split(string separator, StringSplitOptions options) betraktar du sekvensen med tecken som en avgränsare. Till exempel "[]ne]-[Tw[]".Split("]-[", StringSplitOptions.None) delas upp i new string[] { "[]ne", "Tw[]" };. Å public static [String::]Split(char[] separator, StringSplitOptions options) andra sidan betraktar varje tecken i separator som en distinkt avgränsare, så matrisens motsvarande delade avkastningar new string[] { "", "", "ne", "", "", "Tw", "", "" }. Därför måste alla nya överbelastningar som accepterar en ReadOnlySpan<char> avgöra om det är strängliknande eller matrisliknande. I allmänhet överensstämmer .NET med det matrisliknande beteendet.

Överväg följande nya String överlagringar som accepterar ett ReadOnlySpan<char> argument som föreslås i 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);

Tänk dessutom på följande ofta definierade tilläggsmetod:

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

För befintliga .NET-körningar tar den här tilläggsmetoden bort den angivna sekvensen från slutet av strängen. På grund av reglerna för överbelastningsmatchning i C# "12345!!!!".TrimEnd("!!!") föredrar du dock den nya TrimEnd överbelastningen framför den befintliga tilläggsmetoden och ändrar resultatet från "12345!" (tar bara bort en fullständig uppsättning med tre utropstecken) till "12345" (tar bort alla utropstecken från slutet).

För att lösa den här pausen fanns det två möjliga sökvägar: Introducera en instansmetod public string TrimEnd(string trimString) som är ett ännu bättre mål eller ta bort den nya metoden. Det första alternativet medför ytterligare risker eftersom det måste avgöra om det returnerar en instans av målsträngen eller alla. Och det finns utan tvekan anropare med befintlig kod som använder varje metod. Därför var det andra alternativet det lämpligaste valet för det här steget i versionscykeln.

Uppringare av String.Trim vilka skickar in enskilda tecken med hjälp av params funktionen, str.Trim(';', ',', '.')till exempel , ser ingen paus. Koden har automatiskt växlat från anrop string.Trim(params char[]) till string.Trim(params ReadOnlySpan<char>). När du återskapar mot GA-versionen av .NET 9 växlar kompilatorn automatiskt tillbaka till överbelastningen char[] .

Uppringare som String.Trim uttryckligen skickar en ReadOnlySpan<char> (eller en typ som är konvertibel till ReadOnlySpan<char> som inte också är konvertibel till char[]) måste ändra sin kod för att anropa Trim efter den här ändringen.

När det gäller String.Split, till skillnad från String.Trim, har den här metoden redan en överlagring som båda föredras framför en tilläggsmetod som accepterar en enskild strängparameter och den nyligen tillagda ReadOnlySpan<char> överbelastningen. Därför bevarades den nya överbelastningen av String.Split .

Kommentar

Du bör återskapa alla sammansättningar som skapats mot .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 eller .NET 9 RC2 för att säkerställa att alla anrop till den borttagna metoden tas bort. Om du inte gör det kan det resultera i en MissingMethodException vid körning.

Version introducerad

.NET 9 GA

Tidigare beteende

Följande kod kompilerad i .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 och .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));

Före .NET 9 Preview 6 gav "prefixinfix"följande kod . För .NET 9 Preview 6 till .NET 9 RC2 gav "prefixin"den i stället :

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

Nytt beteende

Följande kod som uttryckligen använder en sektor av en matris kompileras inte längre, eftersom det inte finns någon lämplig överlagring för den att anropa:

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

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

Kod som har en tilläggsmetod string TrimEnd(this string target, this string suffix) har nu samma beteende som i .NET 8 och tidigare versioner. Det innebär att det ger "prefixinfix".

Typ av icke-bakåtkompatibel ändring

Den här ändringen kan påverka binär kompatibilitet och källkompatibilitet.

Orsak till ändringen

Många projekt har tilläggsmetoder som upplever beteendeförändringar efter omkompilering. Den negativa effekten av dessa nya instansmetoder bedömdes uppväga deras positiva fördelar.

Kompilera om alla projekt som har skapats mot .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 eller .NET 9 RC2. Om projektet kompileras utan fel krävs inget ytterligare arbete. Om projektet inte längre kompileras justerar du koden. Ett möjligt ersättningsexempel visas här:

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

...

return input.Trim(s_trimChars);

Berörda API:er

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