String.Trim*(params ReadOnlySpan<char>) túlterhelések eltávolítva

A .NET-ökoszisztémában ReadOnlySpan<char> a következőt jelölheti:

  • Egy adott karaktersorozat, gyakran egy nagyobb System.String példány szeleteként.
  • Egyetlen karakterből álló gyűjtemény, amely gyakran egy char[]szelet.

A .NET 9 korábbi kiadásai túlterhelést adtak a params ReadOnlySpan<T> már túlterhelt params T[] metóduscsoportokhoz. Bár ez a túlterhelés bizonyos metóduscsoportok esetében pozitív kiegészítés volt, a kettős jellege ReadOnlySpan<char> zavart okozhat egy olyan metóduscsoport esetében, amely elfogadja az a char[] és a String (ugyanabban a helyzetben lévő) metóduscsoportot, és másképp kezeli őket. Példaként public static string [String::]Split(string separator, StringSplitOptions options) a karakterek sorozatát tekinti elválasztónak. Például "[]ne]-[Tw[]".Split("]-[", StringSplitOptions.None) felosztja a következőre new string[] { "[]ne", "Tw[]" };: . Másrészt public static [String::]Split(char[] separator, StringSplitOptions options) az egyes karaktereket separator különálló elválasztóként tekinti, így a tömb-egyenértékű felosztás hozamot new string[] { "", "", "ne", "", "", "Tw", "", "" }eredményez. Ezért minden olyan új túlterhelésnek, amely elfogad egy ReadOnlySpan<char> adottat, el kell döntenie, hogy sztringszerű vagy tömbszerű-e. Általánosságban elmondható, hogy a .NET megfelel a tömbszerű viselkedésnek.

Vegye figyelembe a következő új String túlterheléseket, amelyek a dotnet/runtime#77873ReadOnlySpan<char>javasolt argumentumot fogadnak el:

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

Emellett vegye figyelembe a következő, gyakran definiált bővítménymetódusokat:

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

A meglévő .NET-futtatókörnyezetek esetében ez a bővítménymetódus eltávolítja a megadott sorozatot a sztring végéről. A C# "12345!!!!".TrimEnd("!!!") túlterhelésfeloldási szabályai miatt azonban inkább az új TrimEnd túlterhelést részesíti előnyben a meglévő bővítménymetódussal szemben, és az eredményt "12345!" (csak három felkiáltójel teljes készletének eltávolításával) "12345" módosítja (az összes felkiáltójelet eltávolítja a végéről).

A törés megoldásához két lehetséges elérési út volt: Egy még jobb célpéldányt tartalmazó példánymetódus public string TrimEnd(string trimString) bevezetése vagy az új metódus eltávolítása. Az első beállítás további kockázattal jár, mivel el kell döntenie, hogy a célsztring egy példányát adja vissza, vagy az összeset. És kétségtelen, hogy vannak olyan hívók, amelyek már meglévő kóddal használják az egyes megközelítéseket. Ezért a második lehetőség volt a legmegfelelőbb választás a kiadási ciklus ezen szakaszához.

Azok a String.Trim hívók, akik például a funkcióval adják át az params egyes karaktereket, str.Trim(';', ',', '.')nem fognak szünetet látni. A kód automatikusan átvált a hívásról string.Trim(params char[]) a string.Trim(params ReadOnlySpan<char>). Amikor újraépíti a .NET 9 ga kiadását, a fordító automatikusan visszaáll a char[] túlterhelésre.

Azoknak a String.Trim hívóknak, akik explicit módon adnak át egy ReadOnlySpan<char> (vagy olyan típust, amely nem konvertálható ReadOnlySpan<char>char[]) a kódjukat úgy kell módosítaniuk, hogy a módosítás után sikeresen meghívják Trim őket.

String.SplitEzzel ellentétben String.Trimez a metódus már túlterheléssel rendelkezik, amelyet előnyben részesít egy olyan bővítménymetódus, amely egyetlen sztringparamétert és az újonnan hozzáadott ReadOnlySpan<char> túlterhelést fogad el. Ezért az új túlterhelés String.Split megőrződött.

Feljegyzés

A .NET 9 Preview 6, a .NET 9 Preview 7, a .NET 9 RC1 vagy a .NET 9 RC2 rendszeren létrehozott összes szerelvényt újra kell építenie, hogy az eltávolított metódusra irányuló hívások törlődjenek. Ennek elmulasztása futásidőben MissingMethodException-t eredményezhet.

Bevezetett verzió

.NET 9 GA

Előző viselkedés

A .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 és .NET 9 RC2 verzióban lefordított alábbi kód:

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

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

A .NET 9 6. előzetes verziója előtt a következő kód jelent meg "prefixinfix". A .NET 9 Preview 6 és .NET 9 RC2 verziók esetében a következőt eredményezte "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");

Új viselkedés

Az alábbi kód, amely explicit módon egy tömb szeletét használja, már nem fordítható le, mivel nincs megfelelő túlterhelés a meghíváshoz:

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

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

A bővítménymetódust string TrimEnd(this string target, this string suffix) tartalmazó kód mostantól ugyanazzal a viselkedéssel rendelkezik, mint a .NET 8-ban és az előző verziókban. Ez azt, hogy a hozamok "prefixinfix".

A kompatibilitástörő változás típusa

Ez a változás befolyásolhatja a bináris kompatibilitást és a forráskompatibilitást.

A változás oka

Számos projekt rendelkezik olyan bővítménymetelyekkel, amelyek viselkedésbeli változásokat tapasztalnak az újrafordítás után. Az új példánymódszerek negatív hatását úgy ítélték meg, hogy meghaladják a pozitív előnyüket.

A .NET 9 Preview 6, a .NET 9 Preview 7, a .NET 9 RC1 vagy a .NET 9 RC2 verzióhoz készült projektek újrafordítása. Ha a projekt hiba nélkül fordít, nincs szükség további munkára. Ha a projekt már nem fordít, módosítsa a kódot. Itt látható egy lehetséges helyettesítési példa:

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

...

return input.Trim(s_trimChars);

Érintett API-k

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