Partager via


Surcharges String.Trim*(params ReadOnlySpan<char>) supprimées

Dans l’écosystème .NET, ReadOnlySpan<char> peut représenter :

  • Séquence spécifique de caractères, souvent en tant que tranche d’une instance plus grande System.String .
  • Collection de caractères uniques, souvent en tant que tranche d’un char[].

Les versions antérieures de .NET 9 ont ajouté params ReadOnlySpan<T> des surcharges aux groupes de méthodes qui avaient déjà une params T[] surcharge. Bien que cette surcharge ait été un ajout positif pour certains groupes de méthodes, la double nature de ReadOnlySpan<char> peut provoquer une confusion pour un groupe de méthodes qui accepte un char[] et un String (dans la même position) et ils sont traités différemment. Par exemple, public static string [String::]Split(string separator, StringSplitOptions options) considère la séquence de caractères comme un séparateur. Par exemple, "[]ne]-[Tw[]".Split("]-[", StringSplitOptions.None) fractionne en new string[] { "[]ne", "Tw[]" };. En revanche, public static [String::]Split(char[] separator, StringSplitOptions options) considère chaque caractère comme separator un séparateur distinct, de sorte que le fractionnement équivalent au tableau génère new string[] { "", "", "ne", "", "", "Tw", "", "" }. Par conséquent, toute nouvelle surcharge qui accepte un ReadOnlySpan<char> doit décider s’il s’agit d’une chaîne ou d’un tableau. En règle générale, .NET est conforme au comportement de type tableau.

Considérez les nouvelles String surcharges suivantes qui acceptent un ReadOnlySpan<char> argument comme proposé dans 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);

En outre, tenez compte de la méthode d’extension couramment définie suivante :

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

Pour les runtimes .NET existants, cette méthode d’extension supprime la séquence spécifiée de la fin de la chaîne. Toutefois, en raison des règles de résolution de surcharge de C#, "12345!!!!".TrimEnd("!!!") préférera la nouvelle TrimEnd surcharge à la méthode d’extension existante et modifiera le résultat ( "12345!" en supprimant uniquement un ensemble complet de trois points d’exclamation) à "12345" (en supprimant toutes les marques d’exclamation de la fin).

Pour résoudre ce saut, il existe deux chemins possibles : introduire une méthode public string TrimEnd(string trimString) d’instance qui est une cible encore meilleure, ou supprimer la nouvelle méthode. La première option présente un risque supplémentaire, car elle doit décider s’il retourne une instance de la chaîne cible ou de l’ensemble d’entre elles. Et il existe sans aucun doute des appelants avec du code existant qui utilise chaque approche. Par conséquent, la deuxième option était le choix le plus approprié pour cette étape du cycle de publication.

Les appelants de String.Trim qui passent des caractères individuels à l’aide de la params fonctionnalité, par exemple, str.Trim(';', ',', '.')ne voient pas de saut. Votre code est automatiquement passé de l’appel string.Trim(params char[]) à string.Trim(params ReadOnlySpan<char>). Lorsque vous régénérez la version en disponibilité générale de .NET 9, le compilateur revient automatiquement à la char[] surcharge.

Les appelants qui String.Trim passent explicitement un ReadOnlySpan<char> (ou un type convertible en ReadOnlySpan<char> ce qui n’est pas également convertible en char[]) doivent modifier leur code pour qu’il l’appelle Trim correctement après cette modification.

Comme pour String.Split, contrairement à String.Trim, cette méthode a déjà une surcharge qui est à la fois préférée à une méthode d’extension acceptant un paramètre de chaîne unique et la surcharge nouvellement ajoutée ReadOnlySpan<char> . Pour cette raison, la nouvelle surcharge a String.Split été conservée.

Remarque

Vous devez reconstruire n’importe quel assembly créé sur .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 ou .NET 9 RC2 pour vous assurer que tous les appels à la méthode supprimée sont supprimés. L’échec de cette opération peut entraîner une MissingMethodException exécution au moment de l’exécution.

Version introduite

.NET 9 GA

Comportement précédent

Le code suivant compilé dans .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 et .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));

Avant .NET 9 Preview 6, le code suivant a généré "prefixinfix". Pour .NET 9 Preview 6 à .NET 9 RC2, il a plutôt produit "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");

Nouveau comportement

Le code suivant qui utilise explicitement une tranche d’un tableau ne se compile plus, car il n’y a pas de surcharge appropriée pour l’appeler :

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

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

Le code qui comprend une méthode string TrimEnd(this string target, this string suffix) d’extension a maintenant le même comportement qu’il avait dans .NET 8 et les versions précédentes. C’est-à-dire qu’il génère "prefixinfix".

Type de changement cassant

Cette modification peut affecter la compatibilité binaire et la compatibilité des sources.

Raison du changement

De nombreux projets ont des méthodes d’extension qui subissent des modifications comportementales après la recompilation. L’impact négatif de ces nouvelles méthodes d’instance a été jugé supérieur à leur avantage positif.

Recompilez tous les projets générés sur .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 ou .NET 9 RC2. Si le projet se compile sans erreur, aucun travail supplémentaire n’est nécessaire. Si le projet ne se compile plus, ajustez votre code. Voici un exemple de substitution possible :

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

...

return input.Trim(s_trimChars);

API affectées

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