Aracılığıyla paylaş


String.Trim*(params ReadOnlySpan<char>) aşırı yüklemeleri kaldırıldı

.NET ekosisteminde şunları ReadOnlySpan<char> temsil edebilir:

  • Genellikle daha büyük System.String bir örneğin dilimi olarak belirli bir karakter dizisi.
  • Genellikle bir dilim olarak tek karakterden oluşan bir char[]koleksiyon.

.NET 9'un önceki sürümleri, zaten aşırı yüklenmiş olan yöntem gruplarına aşırı yüklemeler eklemişti params ReadOnlySpan<T>params T[] . Bu aşırı yükleme bazı yöntem grupları için olumlu bir ekleme olsa da, çiftin doğası ReadOnlySpan<char> a char[] ve (aynı konumda) kabul eden ve farklı şekilde ele alınan bir String yöntem grubu için karışıklığa neden olabilir. Örneğin, public static string [String::]Split(string separator, StringSplitOptions options) karakter dizisini bir ayırıcı olarak ele alır. Örneğin, "[]ne]-[Tw[]".Split("]-[", StringSplitOptions.None) içine new string[] { "[]ne", "Tw[]" };bölünür. Öte yandan, public static [String::]Split(char[] separator, StringSplitOptions options) içindeki separator her karakteri ayrı bir ayırıcı olarak değerlendirir, bu nedenle dizi eşdeğeri bölme verimini verir new string[] { "", "", "ne", "", "", "Tw", "", "" }. Bu nedenle, kabul eden tüm yeni aşırı yüklemelerin ReadOnlySpan<char> dizeye benzer mi yoksa dizi benzeri mi olduğuna karar vermeleri gerekir. Genel olarak, .NET dizi benzeri davranışa uygundur.

dotnet/runtime#77873'teString önerilen bir ReadOnlySpan<char> bağımsız değişkeni kabul eden aşağıdaki yeni aşırı yüklemeleri göz önünde bulundurun:

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

Ayrıca, aşağıdaki yaygın olarak tanımlanan uzantı yöntemini göz önünde bulundurun:

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

Var olan .NET çalışma zamanları için bu uzantı yöntemi, belirtilen diziyi dizenin sonundan kaldırır. Ancak, C# öğesinin aşırı yükleme çözümleme kuralları nedeniyle yeni "12345!!!!".TrimEnd("!!!") aşırı yüklemeyi mevcut uzantı yöntemi yerine tercih TrimEnd eder ve sonucu "12345!" (yalnızca üç ünlem işaretinden oluşan tam bir kümeyi kaldırarak) "12345" olarak değiştirir (sonundan tüm ünlem işaretlerini kaldırır).

Bu kesmeyi çözmek için iki olası yol vardı: Daha da iyi bir hedef olan bir örnek yöntemini public string TrimEnd(string trimString) tanıtın veya yeni yöntemi kaldırın. İlk seçenek, hedef dizenin bir örneğini mi yoksa tümünü mü döndüreceğine karar vermesi gerektiğinden ek risk taşır. Ve kuşkusuz her yaklaşımı kullanan mevcut koda sahip arayanlar vardır. Bu nedenle, ikinci seçenek yayın döngüsünün bu aşaması için en uygun seçenekti.

Özelliği kullanarak String.Trim tek tek karakterleri geçiren arayanlar params (örneğin, str.Trim(';', ',', '.')) bir kesme görmez. Kodunuz otomatik olarak çağrısından string.Trim(params char[]) öğesine string.Trim(params ReadOnlySpan<char>)geçmiş olur. .NET 9'un GA sürümüne karşı yeniden derleme yaptığınızda, derleyici otomatik olarak aşırı yüklemeye char[] geri döner.

Açıkça bir String.Trim (veya dönüştürülebilir olarak dönüştürülebilir ReadOnlySpan<char>ReadOnlySpan<char> olmayan bir tür) geçirenlerinchar[], bu değişiklikten sonra kodunu başarılı bir şekilde çağıracak Trim şekilde değiştirmeleri gerekir.

String.Split'de olduğu gibiString.Trim, bu yöntemin zaten tek bir dize parametresini kabul eden bir vardır. Bu nedenle, yeni aşırı yüklemesi String.Split korundu.

Not

Kaldırılan yönteme yapılan tüm çağrıların kaldırıldığından emin olmak için .NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 veya .NET 9 RC2'ye göre oluşturulmuş tüm derlemeleri yeniden oluşturmanız gerekir. Bunun yapılmaması çalışma zamanında bir MissingMethodException ile sonuçlanabilir.

Sürüm kullanıma sunulmuştur

.NET 9 GA

Önceki davranış

.NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 ve .NET 9 RC2'de derlenen aşağıdaki kod:

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

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

.NET 9 Preview 6'nın öncesinde aşağıdaki kod kullanıma sunulmuştur "prefixinfix". .NET 9 Preview 6 ile .NET 9 RC2 arasında bunun yerine şunu verdi "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");

Yeni davranış

Bir dizi dilimini açıkça kullanan aşağıdaki kod artık derlenmez çünkü çağıracak uygun bir aşırı yükleme yoktur:

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

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

Uzantı yöntemini string TrimEnd(this string target, this string suffix) içeren kod artık .NET 8 ve önceki sürümlerde olduğu gibi aynı davranışa sahiptir. Yani, verir "prefixinfix".

Hataya neden olan değişikliğin türü

Bu değişiklik ikili uyumluluğu ve kaynak uyumluluğunu etkileyebilir.

Değişiklik nedeni

Birçok proje, yeniden derledikten sonra davranış değişiklikleriyle karşılaşan uzantı yöntemlerine sahiptir. Bu yeni örnek yöntemlerinin olumsuz etkisinin olumlu faydalarından daha fazla olduğu kabul edildi.

.NET 9 Preview 6, .NET 9 Preview 7, .NET 9 RC1 veya .NET 9 RC2 ile oluşturulmuş tüm projeleri yeniden derleyin. Proje hata olmadan derleniyorsa, başka bir çalışma gerekmez. Proje artık derlenemiyorsa kodunuzu ayarlayın. Olası bir değiştirme örneği burada gösterilmiştir:

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

...

return input.Trim(s_trimChars);

Etkilenen API’ler

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