String.Trim*(params ReadOnlySpan<char>) 多載已移除
在 .NET 生態系統中, ReadOnlySpan<char>
可以代表:
- 特定字元序列,通常是較大 System.String 實例的配量。
- 單一字元的集合,通常是 的配
char[]
量。
舊版 .NET 9 已將多載新增 params ReadOnlySpan<T>
至已經有 params T[]
多載的方法群組。 雖然這個多載是某些方法群組的正加法,但的 ReadOnlySpan<char>
雙重本質可能會對接受 char[]
和 String (處於相同位置) 的方法群組造成混淆,而且它們會以不同的方式處理。 例如, public static string [String::]Split(string separator, StringSplitOptions options)
將字元序列視為一個分隔符。 例如, "[]ne]-[Tw[]".Split("]-[", StringSplitOptions.None)
分割成 new string[] { "[]ne", "Tw[]" };
。 另一方面, public static [String::]Split(char[] separator, StringSplitOptions options)
會將 中的每個 separator
字元視為相異分隔符,因此陣列對等分割會產生 new string[] { "", "", "ne", "", "", "Tw", "", "" }
。 因此,任何接受 ReadOnlySpan<char>
的新多載,必須判斷它是否為類似字串或類似陣列的多載。 一般而言,.NET 符合類似數位的行為。
請考慮下列接受 dotnet/runtime#77873 中所建議自變數的新String多載ReadOnlySpan<char>
:
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);
此外,請考慮下列常用的擴充方法:
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;
}
}
對於現有的 .NET 運行時間,這個擴充方法會從字串結尾移除指定的序列。 不過,由於 C# 的多載解析規則, "12345!!!!".TrimEnd("!!!")
會偏好使用新的 TrimEnd
多載而不是現有的擴充方法,並將結果從 "12345!"
(只移除一組完整的三個驚嘆號) 變更為 "12345"
(從結尾移除所有驚歎號)。
若要解決此中斷,有兩個可能的路徑:引進實例方法 public string TrimEnd(string trimString)
,這是更好的目標,或移除新的方法。 第一個選項會帶來額外的風險,因為它需要決定是否傳回目標字串的一個實例或全部實例。 而且毫無疑問,有使用每個方法的現有程序代碼呼叫端。 因此,第二個選項是發行週期這個階段最適當的選擇。
使用params
功能傳入個別字元的呼叫端String.Trim,例如 str.Trim(';', ',', '.')
,不會看到中斷。 您的程式代碼會自動從呼叫 string.Trim(params char[])
切換到 string.Trim(params ReadOnlySpan<char>)
。 當您針對 .NET 9 的 GA 版本重建時,編譯程式會自動切換回 char[]
多載。
明確傳入的呼叫端String.Trim(或可轉換成ReadOnlySpan<char>
且不可轉換成char[]
的類型)必須變更其程序代碼,才能在此變更之後成功呼叫Trim
。ReadOnlySpan<char>
至於 String.Split,不同於 String.Trim,這個方法已經有一個多載,兩者都優先於接受單一字元串參數和新加入ReadOnlySpan<char>
的多載方法。 基於這個理由,會保留 的新 多載 String.Split 。
注意
您應該重建針對 .NET 9 Preview 6、.NET 9 Preview 7、.NET 9 RC1 或 .NET 9 RC2 建置的任何元件,以確保移除任何對已移除方法的呼叫。 若無法這麼做,可能會導致 MissingMethodException 在執行時間發生 。
導入的版本
.NET 9 GA
先前的行為
下列程序代碼在 .NET 9 Preview 6、.NET 9 Preview 7、.NET 9 RC1 和 .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));
在 .NET 9 Preview 6 之前,下列程式代碼會產生 "prefixinfix"
。 針對 .NET 9 Preview 6 到 .NET 9 RC2,它會改為產生 "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");
新的行為
下列明確使用陣列配量的程式代碼不再編譯,因為沒有適當的多載可供它呼叫:
private static readonly char[] s_allowedWhitespace = { ' ', '\t', '\u00A0', '\u2000' };
// Only remove the ASCII whitespace.
str = str.Trim(s_allowedWhitespace.AsSpan(0, 2));
具有擴充方法 string TrimEnd(this string target, this string suffix)
的程式代碼現在具有與 .NET 8 和舊版相同的行為。 也就是說,它會產生 "prefixinfix"
。
中斷性變更的類型
變更原因
許多專案都有擴充方法,其會在重新編譯之後體驗行為變更。 這些新實例方法的負面影響被認為超過其正面好處。
建議的動作
重新編譯針對 .NET 9 Preview 6、.NET 9 Preview 7、.NET 9 RC1 或 .NET 9 RC2 建置的任何專案。 如果項目編譯時沒有錯誤,則不需要進一步的工作。 如果專案不再編譯,請調整您的程序代碼。 以下顯示可能的替代範例:
-private static ReadOnlySpan<char> s_trimChars = [ ';', ',', '.' ];
+private static readonly char[] s_trimChars = [ ';', ',', '.' ];
...
return input.Trim(s_trimChars);
受影響的 API
System.String.Trim(System.ReadOnlySpan{System.Char})
System.String.TrimEnd(System.ReadOnlySpan{System.Char})
System.String.TrimStart(System.ReadOnlySpan{System.Char})