Sdílet prostřednictvím


String.Trim*(params ReadOnlySpan<char>) přetížení odebraná

V ekosystému ReadOnlySpan<char> .NET může představovat:

  • Konkrétní posloupnost znaků, často jako řez větší System.String instance.
  • Kolekce jednotlivých znaků, často jako řez .char[]

Dřívější verze rozhraní .NET 9 přidaly params ReadOnlySpan<T> přetížení do skupin metod, které již měly params T[] přetížení. I když toto přetížení bylo pozitivním doplněním některých skupin metod, duální povaha ReadOnlySpan<char> může způsobit nejasnost pro skupinu metod, která přijímá a char[] a ( String ve stejné pozici) a jsou zpracovávány odlišně. Jako příklad public static string [String::]Split(string separator, StringSplitOptions options) se považuje posloupnost znaků za jeden oddělovač. Například "[]ne]-[Tw[]".Split("]-[", StringSplitOptions.None) rozdělení na new string[] { "[]ne", "Tw[]" };. Na druhou stranu public static [String::]Split(char[] separator, StringSplitOptions options) se každý znak považuje za separator odlišný oddělovač, takže rozdělení ekvivalentní pole je výsledkem new string[] { "", "", "ne", "", "", "Tw", "", "" }. Proto se jakékoli nové přetížení, které přijímá ReadOnlySpan<char> , musí rozhodnout, zda se jedná o řetězec-like nebo pole-like. Obecně řečeno, .NET odpovídá chování podobné poli.

Zvažte následující nová String přetížení, která přijímají argument podle návrhu ReadOnlySpan<char> v 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);

Kromě toho zvažte následující běžně definovanou metodu rozšíření:

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

Pro existující moduly runtime .NET tato metoda rozšíření odebere zadanou sekvenci z konce řetězce. Vzhledem k pravidlům překladu přetížení jazyka C# "12345!!!!".TrimEnd("!!!") však upřednostní nové TrimEnd přetížení před existující metodou rozšíření a změní výsledek ( "12345!" odebrání pouze úplné sady tří vykřičníků) na "12345" (odebrání všech vykřičníků z konce).

K vyřešení tohoto přerušení došlo ke dvěma možným cestám: Zavedení metody public string TrimEnd(string trimString) instance, která je ještě lepším cílem, nebo odebrání nové metody. První možnost nese další riziko, protože se musí rozhodnout, jestli vrátí jednu instanci cílového řetězce, nebo všechny z nich. A existují nepochybně volající se stávajícím kódem, který používá každý přístup. Proto byla druhá možnost nejvhodnější volbou pro tuto fázi cyklu vydávání verzí.

Volající, String.Trim kteří předávají jednotlivé znaky pomocí params funkce, str.Trim(';', ',', '.')například , neuvidí konec. Váš kód se automaticky přepne z volání string.Trim(params char[]) na string.Trim(params ReadOnlySpan<char>). Při opětovném sestavení proti verzi GA rozhraní .NET 9 kompilátor automaticky přepne zpět na char[] přetížení.

Volající, String.Trim kteří explicitně předávají ReadOnlySpan<char> (nebo typ, který se přepojí na ReadOnlySpan<char> nepřepočítané char[]) musí změnit kód, aby po této změně úspěšně volal Trim .

Co se týče String.Split, na rozdíl od String.Trim, tato metoda již má přetížení , které je preferováno nad rozšiřující metodou přijetí jednoho řetězcového parametru a nově přidané ReadOnlySpan<char> přetížení. Z tohoto důvodu se zachovalo nové přetížení String.Split .

Poznámka:

Pokud chcete zajistit odebrání všech volání odebrané metody, měli byste znovu sestavit všechna sestavení sestavená pro .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 nebo .NET 9 RC2. Pokud to neuděláte, může to vést k MissingMethodException době běhu.

Zavedená verze

Obecná dostupnost .NET 9

Předchozí chování

Následující kód zkompilovaný v .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 a .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));

Před .NET 9 Preview 6 se vyvolil "prefixinfix"následující kód . Pro .NET 9 Preview 6 až .NET 9 RC2 místo toho přinesl "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");

Nové chování

Následující kód, který explicitně používá řez pole, se už nekompiluje, protože neexistuje vhodné přetížení pro volání:

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

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

Kód, který obsahuje metodu string TrimEnd(this string target, this string suffix) rozšíření, teď má stejné chování jako v .NET 8 a předchozích verzích. To znamená, že přináší "prefixinfix".

Typ zásadní změny

Tato změna může mít vliv na kompatibilitu binárních souborů a kompatibilitu zdroje.

Důvod změny

Mnoho projektů má rozšiřující metody, které po opětovném zkompilování dochází ke změnám chování. Negativní dopad těchto nových metod instancí byl považován za převažovaný nad jejich pozitivním přínosem.

Překompilujte všechny projekty vytvořené v .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 nebo .NET 9 RC2. Pokud se projekt zkompiluje bez chyb, nevyžaduje se žádná další práce. Pokud se projekt už nekompiluje, upravte kód. Tady je příklad možné náhrady:

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

...

return input.Trim(s_trimChars);

Ovlivněná rozhraní API

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