Champion 期數:https://github.com/dotnet/csharplang/issues/8887
動機
字典表達功能已識別出集合表達式需要傳遞使用者指定的資料,以配置最終集合的行為。 具體來說,字典允許使用者自訂鍵的比較方式,用來定義鍵之間的相等,以及排序或雜湊(分別是排序或雜湊集合)。 這個需求在建立任何字典類型(例如 D d = new D(...)、 D d = D.CreateRange(...)IDictionary<...> d = <synthesized dict>甚至 ) 時都適用
為支持此點,會提出一個新 with(...arguments...) 元素作為集合表達式的第一個元素,如下:
Dictionary<string, int> nameToAge = [with(comparer), .. d1, .. d2, .. d3];
- 當轉換成
new CollectionType(...)呼叫時,這些資料...arguments...用來決定適當的建構子,並相應地傳遞。 - 在轉換為呼叫
CollectionFactory.Create時,這些...arguments...參數會先ReadOnlySpan<ElementType>以元素參數傳遞,所有元素都用來判斷適當的Create超載,並相應地傳遞。 - 當轉換到介面(例如
IDictionary<,>)時,只允許一個參數。 它實作了知名的 BCL 比較介面之一,並用於控制最終實例的金鑰比較語意。
此語法被選為:
- 這樣所有資訊都集中在語法內
[...]。 確保程式碼仍清楚顯示正在建立一個集合。 - 這並不代表要呼叫
new建構子(畢竟所有集合並非都是這樣建立的)。 - 這並不代表要像後綴
with { ... }那樣多次建立或複製集合的數值。 - 不會扭曲操作順序,尤其是在 C# 從左到右的表達式評估語意排序下。 例如,在評估用來填充集合的表達式 後 ,它不會評估用於構造集合的參數。
- 不會強迫使用者閱讀到(可能很大的)集合表達式的末尾以判斷核心行為語意。 例如,必須看到一本百行字典的結尾,結果發現,沒錯,它用的是正確的金鑰比較器。
- 既不含蓄,也不過度冗長。 例如,用
;代替,來表示參數,是個很容易被忽略的語法。with()只新增 6 個字元,且在關鍵字的語法著色with下會非常突出。 - 讀起來很順暢。 「這是一個包含這些論點的集合表達,包含這些元素。」
- 解決了字典和集合都需要比較器的問題。
- 確保任何用戶傳遞參數的需求,或是我們自己未來超越比較器的需求,都已被處理。
- 不會與現有程式碼(用於 https://grep.app/ 搜尋)衝突。
設計理念
以下章節涵蓋先前的設計哲學討論。 包括為什麼某些表格會被拒絕。
我們可以從兩個主要方向來提供這些使用者定義的資料。 第一種是比較空間中的值(我們定義為繼承自 BCL IComparer<T> 或IEqualityComparer<T>型別的型別)。 第二種是提供一種通用機制,在建立集合表達式時,為最終被調用的 API 提供任意參數。 主要字 典表達 式規範展示了如何實現前者,而本規範則試圖實現後者。
對於僅僅通過比較 者的 解法的檢視,發現若將這些方法擴展到 任意論證,則存在其方法的弱點。 例如:
重複使用 元素 語法,就像我們對形式
[StringComparer.OrdinalIgnoreCase, "mads": 21]: 所做的。 這在比較KeyValuePair<,>者不會繼承常見型態的領域運作良好。 但在一個世界裡,可能會有:HashSet<object> h = [StringComparer.OrdinalIgnoreCase, "v"]。 這是傳遞比較器嗎? 或者嘗試將兩個物件值放入集合?將參數與有細微語法的元素分開(例如用分號代替逗號來分隔
[comparer; v1])。 這可能導致使用者誤寫[1; 2](結果收到一個集合,該集合將「1」作為「容量」參數List<>,且只包含單一值「2」),而使用者本意[1, 2]是兩個元素。
因此,為了支持任意論點,我們認為需要更明確的語法來更明確地界定這些數值。 在這個領域中,還有其他幾種設計上的考量。 以下內容不分先後:
解決方案不要模糊不清,避免與現今人們用集合式時常用的程式碼斷裂。 例如:
List<Widget> c = [new(...), w1, w2, w3];這在現今
new(...)是合法的,表達式指的是「隱含物件建立」,會創造一個新的小工具。 我們無法將此資料重新利用來傳遞 的建List<>構子,因為這 肯定 會破壞現有程式碼。語法不能延伸到結構之外
[...]。 例如:HashSet<string> s = [...] with ...;這些語法可以解釋為集合先被建立,然後再以不同形式重建,這意味著資料需要多次轉換,且可能帶來不必要的更高成本(即使這並非實際輸出)。
在這個領域中,這個潛在關鍵字會讓人感到非常混淆。
new因為[...]已經 表示 新物件被 建立,且集合表達式的轉換可能會透過非建構子 API(例如 Create 方法 模式)進行。希望解決方案不要過於冗長。 集合表達式的核心價值主張之一是 簡潔。 所以如果表單加入大量語法支架,會感覺像是倒退,且會削弱使用集合式表達式的價值主張,而非直接呼叫現有 API 來建立集合。
請注意,像 new([...], ...) 這樣的語法會違反上述「2」和「3」兩個。 它會讓人覺得我們正在呼叫建構子(其實可能不是), 並且 暗示一個已建立的集合表達式會傳遞給該建構子,但這絕對不是。
基於上述所有,出現了少數幾個選項,認為能解決通過論證的需求,同時不超出集合表達式的目標範圍。
[with(...arguments...)] 設計
Syntax:
collection_element
: expression_element
| spread_element
+ | with_element
;
+with_element
+ : 'with' argument_list
+ ;
這種語法產生立即引入了句法上的歧義。 類似於與expression_element(此處解釋)之間的歧spread_element義,與expression_element之間存在直接的句法歧義with_element。
具體而言, with(<arguments>) 既是 的 with_element生產體,也可透過 expression_element -> expression -> ... -> invocation_expression達到 。 collection_elements有一條簡單的總體規則。 具體來說,如果元素 在詞彙上 以符號序列 with( 開始,則它總是被視為一個 with_element。
這有兩個好處。 首先,編譯器實作只需查看緊接後面的標記,就能判斷要解析哪種元素。 其次,相對地,使用者可以輕鬆理解自己擁有的元素類型,無需在腦中分析後續內容以判斷是否應視為 a with_element 或 expression_element。
範例
這樣的例子有:
// With an existing type:
// Initialize to twice the capacity since we'll have to add
// more values later.
List<string> names = [with(capacity: values.Count * 2), .. values];
這些表格看起來讀起來還算不錯。 在所有這些情況下,程式碼都是「建立一個集合表達式,並用以下參數傳遞來控制最終實例,然後用來填充該實例的後續元素。 例如,第一行「建立一個字串清單,其容量是即將被擴展的值數的兩倍」。
重要的是,這段程式碼幾乎不像 [arg; element],像 ,這樣容易被忽略,同時也減少冗長,並有很大的彈性可以傳遞任何想要的參數。
這 技術上 來說會是一個突破性變更,也 with(...)可能是 對既有方法 with的呼叫。 然而,與已知且推薦的隱式型別建立值不同new(...),with(...)作為方法名稱的機率較低,且違反了 .Net 方法命名。 即使使用者真的有這種方法,他們也能繼續使用現有方法 @with(...)。
我們將此 with(...) 元素翻譯為:
List<string> names = [with(/*capacity*/10), ...]; // translates to:
// argument_list *becomes* the argument list for the
// constructor call.
__result = new List<string>(10); // followed by normal initialization
// or
IList<string> names2 = [with(capacity: 20), ...]; // translates to:
__result = new List<string>(20);
換句話說,如果我們呼叫建構子,argument_list參數會傳給適當的建構子;如果呼叫該方法,則會傳給適當的「創建方法」。 我們也會允許在實例化目標字典介面類型時,提供從 BCL 比較 器 類型繼承的單一參數,以控制其行為。
轉換次數
集合式的 轉換 區段更新如下:
> A struct or class type that implements System.Collections.IEnumerable where:
- * The type has an applicable constructor that can be invoked with no arguments, and the constructor is accessible at the location of the collection expression.
+ a. the collection expression has no `with_element` and the type has an applicable constructor
+ that can be invoked with no arguments, accessible at the location of the collection expression. or
+ b. the collection expression has a `with_element` and the type has at least one constructor
+ accessible at the location of the collection expression.
請注意,argument_listwith_element該中實際的論點不會影響轉換是否存在。 只是存在或缺 with_element 失本身。 這裡的直覺很簡單,如果集合表達式沒有 arg(例如 [x, y, z]),那麼要能夠呼叫建構子而不使用 args,就必須是 。 如果 是 , [with(...), x, y, z] 則可呼叫相應的建構子。 這也表示無法用無參數建構 子調用 的型別 , 也可以與集合表達式一起使用,但 前提是 該集合表達式 with_element包含 。
遺囑如何影響建築的with_element實際判斷如下。
建築
施工更新如下。
集合表達式的元素依序從左到右計算。 在 集合論元中,論元依序從左到右進行評估。 每個元素或參數僅被評估一次,後續引用則參考此初始評估結果。
若包含 collection_arguments 且不是集合表達式的第一個元素,則會報告編譯時錯誤。
若 參數清單 包含 任何動態型 別的值,則會報告編譯時錯誤(LDM-2025-01-22)。
建構函數
如果目標型別是實作 的結構型或類別型別,且目標型別沒有 create 方法,且目標型別不是通用參數型別,則:System.Collections.IEnumerable
- 超載解析用來從候選實例中找出最佳的實例建構子。
- 候選建構子集合是所有在目標類型上宣告且相對於參數 列表 適用的可存取實例建構子,且定義於 相關函式成員中。
- 若找到最佳實例建構子,則會以 參數清單調用該建構子。
- 若建構子有
params參數,呼叫可為擴展形式。
- 若建構子有
- 否則,將報告綁定錯誤。
// List<T> candidates:
// List<T>()
// List<T>(IEnumerable<T> collection)
// List<T>(int capacity)
List<int> l;
l = [with(capacity: 3), 1, 2]; // new List<int>(capacity: 3)
l = [with([1, 2]), 3]; // new List<int>(IEnumerable<int> collection)
l = [with(default)]; // error: ambiguous constructor
CollectionBuilderAttribute 方法
如果目標型別是帶有 create 方法的型別,則:
- 利用過載解析來從候選中決定最佳的建立方法。
- 針對目標類型的每個 create 方法 ,我們定義一個投影 方法 ,其簽名與 create 方法相同,但 不含最後一個參數。
- 候選投影方法集合是指相對於適用函數成員中定義的參數列表適用的投影方法。
- 若找到最佳投影方法,則會呼叫相應的 create 方法,並附上包含元素的參數列表
ReadOnlySpan<T>。 - 否則,將報告綁定錯誤。
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> { ... }
class MyBuilder
{
public static MyCollection<T> Create<T>(ReadOnlySpan<T> elements);
public static MyCollection<T> Create<T>(IEqualityComparer<T> comparer, ReadOnlySpan<T> elements);
}
MyCollection<string> c1 = [with(GetComparer()), "1", "2"];
// IEqualityComparer<string> _tmp1 = GetComparer();
// ReadOnlySpan<string> _tmp2 = ["1", "2"];
// c1 = MyBuilder.Create<string>(_tmp1, _tmp2);
MyCollection<string> c2 = [with(), "1", "2"];
// ReadOnlySpan<string> _tmp3 = ["1", "2"];
// c2 = MyBuilder.Create<string>(_tmp3);
CollectionBuilderAttribute:建立方法
對於目標型別定義有[CollectionBuilder]屬性的集合表達式,建立方法如下,並由集合表達式更新:create methods。
屬性
[CollectionBuilder(...)]指定建 構 器型別及方法 名稱 ,以呼叫以建構該集合型別的實例。產生器類型 必須是非泛型
class或struct。首先,確定套用的 建立方法
CM的集合。 它包含符合下列需求的方法:
- 方法必須具有在
[CollectionBuilder(...)]屬性中指定的名稱。- 方法必須直接在 建構器類型 上定義。
- 方法必須
static。- 使用集合表達式時,必須能夠存取 方法。
- 方法的 元數 必須符合集合類型的 元數。
- 該方法必須有一個型別
System.ReadOnlySpan<E>為 的最後參數,並以值傳遞。- 同一性轉換、隱含參考轉換,或 裝箱轉換,從方法的傳回型別轉換為 集合類型。
基底類型或介面上宣告的方法會被忽略,而不是
CM集的一部分。
對於目標型別 的
C<S0, S1, …>,其中的 型別宣告C<T0, T1, …>具有相關聯的 產生器方法B.M<U0, U1, …>(),目標型別的 泛型型別自變數 會按順序套用,從最外層的包含型別到最內層,應用於 產生器方法。
與早期演算法的主要差異有:
- 建立方法可能在參數前
ReadOnlySpan<E>有額外參數。 - 支援多種建立方法。
介面目標類型
如果目標型別是 介面型態,則:
過載解析用來決定最佳候選方法簽名。
候選簽章集合是指以下針對目標介面,且相對於適用函式成員中定義的參數列表適用的簽章。
Interfaces 候選人簽名 IEnumerable<E>IReadOnlyCollection<E>IReadOnlyList<E>()(無參數)ICollection<E>IList<E>List<E>()List<E>(int)
若找到最佳方法簽名,語意如下:
- 和 的
IEnumerable<E>IReadOnlyCollection<E>IReadOnlyList<E>候選簽名簡單且()意義相同,完全沒有該with()元素。 - 與 的
IList<T>候選簽名是 和List<T>(int)的 建構子簽名List<T>()。ICollection<T>在構造該值(參見 可變介面轉換)時,會呼叫相應List<T>的建構子。 - 否則,將報告綁定錯誤。
Dictionary-Interface 目標類型
此處指定為定義於 https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md的特徵。
上述清單經過擴充,包含以下項目:
| Interfaces | 候選人簽名 |
|---|---|
IReadOnlyDictionary<K, V> |
() (無參數)(IEqualityComparer<K>? comparer) |
IDictionary<K, V> |
Dictionary<K, V>()Dictionary<K, V>(int)Dictionary<K, V>(IEqualityComparer<K>)Dictionary<K, V>(int, IEqualityComparer<K>) |
若找到最佳方法簽名,語意如下:
- 的
IReadOnlyDictionary<K, V>候選簽名為()(與完全沒有該with()元素的意義相同)、以及(IEqualityComparer<K>)。 此比較器將用於適當地雜湊並比較編譯器選擇建立的目標字典中的鍵(參見 不可變介面轉換)。 - 的
IDictionary<T>候選簽名是 、Dictionary<K, V>(int)和Dictionary<K, V>(IEqualityComparer<K>)Dictionary<K, V>(int, IEqualityComparer<K>)構造子的簽名Dictionary<K, V>()。 在構造該值(參見 可變介面轉換)時,會呼叫相應Dictionary<K, V>的建構子。 - 否則,將報告綁定錯誤。
IDictionary<string, int> d;
IReadOnlyDictionary<string, int> r;
d = [with(StringComparer.Ordinal)]; // new Dictionary<string, int>(StringComparer.Ordinal)
r = [with(StringComparer.Ordinal)]; // new $PrivateImpl<string, int>(StringComparer.Ordinal)
d = [with(capacity: 2)]; // new Dictionary<string, int>(capacity: 2)
r = [with(capacity: 2)]; // error: 'capacity' parameter not recognized
d = [with()]; // Legal: empty arguments supported for interfaces
其他目標類型
若目標型別為其他型別,則即使函數為空,也會報告參數 清單的綁定錯誤。
Span<int> a = [with(), 1, 2, 3]; // error: arguments not supported
Span<int> b = [with([1, 2]), 3]; // error: arguments not supported
int[] a = [with(), 1, 2, 3]; // error: arguments not supported
int[] b = [with(length: 1), 3]; // error: arguments not supported
參考安全
我們會調整 collection-expressions.md#ref-safety 規則以考慮該元素。with()
另見 §16.4.15 安全上下文限制。
建立方法
本節適用於目標型別符合 CollectionBuilderAttribute 方法中定義約束的集合表達式。
安全上下文是透過修改 collection-expressions.md#ref-safety(粗體表示的變更)中的一個子句來決定的:
方法參數必須符合約束,適用於集合式。 與上述 安全上下文 判定類似, 方法參數必須符合 約束,應用方式是將集合表達式視為創建方法的調用,其中參數為 with() 元素參數,接著集合表達式作為最後參數的參數。
建構子呼叫
本節適用於目標型別符合 建構子中定義約束的集合表達式。
對於以下形式的 ref struct 類型的 集合表達式:
[with(a₁, a₂, ..., aₙ), e₁, e₂, ..., eₙ]
集合表達式的安全 上下文 是以下表達式中最狹窄的安全 上下文 :
- 一個物件建立表達式
new C(a₁, a₂, ..., aₙ),其中C是目標類型 - 元素表達
e₁, e₂, ..., eₙ式(無論是表達式本身,或是擴散元素的擴散值)。
方法參數必須符合約束,適用於集合式。 此限制是透過將集合表達式視為依據 low-level-struct-improvements.md#rules-for-object-initializers 形式new C(a₁, a₂, ..., aₙ) { e₁, e₂, ..., eₙ }建立的物件來套用。
- 表達式元素被視為集合元素的初始化器。
- 擴散元素也類似地處理,暫時假設
C有方法Add(SpreadType spread),其中SpreadType是擴散值的類型。
已解答的問題
dynamic 引數
是否應該允許有型 dynamic 別的論證? 這可能需要使用執行時綁定器來解決超載,這會讓限制候選物件集合變得困難,例如用於集合建置器的情況。
解決: 不允許。 LDM-2025-01-22
with() 破解零錢
提議 with() 的元素是破壞性變更。
object x, y, z = ...;
object[] items = [with(x, y), z]; // C#13: ok; C#14: error args not supported for object[]
object with(object x, object y) { ... }
確認破壞性變更是否可接受,以及破壞性變更是否應該綁定語言版本。
解決: 編譯早期語言版本時,保留先前的行為(無破壞性變更)。 LDM-2025-03-17
參數應該影響集合式的轉換嗎?
集合論元及適用方法是否應該影響集合表達式的可轉換性?
Print([with(comparer: null), 1, 2, 3]); // ambiguous or Print<int>(HashSet<int>)?
static void Print<T>(List<T> list) { ... }
static void Print<T>(HashSet<T> set) { ... }
如果參數根據適用方法影響可轉換性,參數也應該影響型別推理。
Print([with(comparer: StringComparer.Ordinal)]); // Print<string>(HashSet<string>)?
作為參考,類似的目標型別 new() 情況也會導致錯誤。
Print<int>(new(comparer: null)); // error: ambiguous
Print(new(comparer: StringComparer.Ordinal)); // error: type arguments cannot be inferred
解決: 在轉換和型別推論中,集合參數應被忽略。 LDM-2025-03-17
集合建構器方法參數順序
對於 集合建構 方法,span 參數應該放在集合參數的前方還是後方?
元素優先可允許參數被宣告為可選。
class MySetBuilder
{
public static MySet<T> Create<T>(ReadOnlySpan<T> items, IEqualityComparer<T> comparer = null) { ... }
}
參數首先允許跨度作為 params 參數,以支持直接以擴展形式呼叫。
var s = MySetBuilder.Create(StringComparer.Ordinal, x, y, z);
class MySetBuilder
{
public static MySet<T> Create<T>(IEqualityComparer<T> comparer, params ReadOnlySpan<T> items) { ... }
}
解決: 元素的跨度參數應該是最後一個參數。 LDM-2025-03-12
與早期語言版本的爭論
在與較早期語言版本編譯時會報告 with() 錯誤,還是會 with 綁定到範圍內的其他符號?
解決: 在與早期語言版本編譯時,集合式內不會有破壞性變更 with 。
LDM-2025-03-17
需要參數的目標類型
集合表達式轉換是否應該支援到必須提供參數的目標型別,因為所有建構子或工廠方法至少需要一個參數?
此類型別可用於包含明確 with() 參數的集合式,但無法用於參數 params 。
例如,考慮以下由工廠方法構造的類型:
MyCollection<object> c;
c = []; // error: no arguments
c = [with(capacity: 1)]; // ok
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : IEnumerable<T> { ... }
class MyBuilder
{
public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, int capacity) { ... }
}
同樣的問題也適用於直接呼叫建構子,如下方範例所示。
然而,對於直接呼叫建構子的目標型態,集合表達式轉換目前需要一個無參數的可建構子呼叫,但在判斷可轉換性時會忽略集合參數。
c = []; // error: no arguments
c = [with(capacity: 1)]; // error: no constructor callable with no arguments?
class MyCollection<T> : IEnumerable<T>
{
public MyCollection(int capacity) { ... }
public void Add(T t) { ... }
// ...
}
解決: 支援轉換成所有建構子或工廠方法都要求參數且轉換時必須 with() 的目標型態。
LDM-2025-03-05
__arglist
應該 __arglist 在 Elements 中得到支援 with() 嗎?
class MyCollection : IEnumerable
{
public MyCollection(__arglist) { ... }
public void Add(object o) { }
}
MyCollection c;
c = [with(__arglist())]; // ok
c = [with(__arglist(x, y)]; // ok
解決: 除非免費,否則不支援 __arglist 收藏內論點。
LDM-2025-03-05
介面類型的論證
介面目標類型是否應該支援參數?
ICollection<int> c = [with(capacity: 4)];
IReadOnlyDictionary<string, int> d = [with(comparer: StringComparer.Ordinal), ..values];
對於 可變 介面類型,選項如下:
- 使用已知實例所需的可存取構造子:
List<T>或Dictionary<K, V>。 - 使用獨立於特定類型的簽章,例如使用
new()和new(int capacity)與ICollection<T>IList<T>(請參見 「建構 」以了解每個介面的潛在簽章)。
使用已知型態的可達構造子具有以下含意:
- 參數名稱、可選性、
params直接取自參數。 - 所有可存取的構造子都包含在內,儘管這對於集合表達式(例如
List(IEnumerable<T>)允許IList<int> list = [with(1, 2, 3)];)可能無用。 - 建構子集合可能依據 BCL 版本而定。
建議:使用知名類型中的可存取建構器。 我們已經保證會使用這些類型,所以這條路自然而然地「脫落」,是構建這些值最清晰且最簡單的路徑。
對於 不可變 介面類型,選項類似:
- 不執行任何動作。 這
- 使用獨立於特定類型的簽名,雖然唯一的情境可能是
new(IEqualityComparer<K> comparer)IReadOnlyDictionary<K, V>C#14..
使用某個已知型別的可存取建構子(可變介面型別的策略)不可行,因為與任何特定現有型別無關聯,最終型別可使用或綜合。 因此,編譯器必須有奇怪的新要求,必須能將任何現有的該類型建構器(即使它在演化中)映射到它實際產生的不可變實例。
建議:使用獨立於特定類型的簽名。 而對於 C# 14,只有 AS IReadOnlyDictionary<K, V> 支援new(IEqualityComparer<K> comparer),是我們認為對可用性和語意要求允許用戶提供此功能至關重要的非可變介面。 未來的 C# 版本可以根據這些合理的理由來擴充這套組合。
解決:https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-23.md
介面目標類型支援參數。 無論是可變介面還是不可變介面,參數集合都會被精心挑選。
預期清單(仍需 LDM 認證)為 介面目標類型
空參數列表
我們是否應該允許某些或所有目標類型使用空參數清單?
空 with() 值等同於沒有 with()。 它可能會讓非空機殼的一致性增加一些,但不會增加任何新功能。
List<int> l = [with()]; // ok? new List<int>()
ImmutableArray<int> m = [with()]; // ok? ImmutableArray.Create<int>()
IList<int> i = [with()]; // ok? new List<int>() or equivalent
IEnumerable<int> e = [with()]; // ok?
int[] a = [with()]; // ok?
Span<int> s = [with()]; // ok?
解決:https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-05-12.md#empty-argument-lists
我們將允許 with() 用於建構子類型和可完全不使用參數呼叫的建構者類型,並為介面(可變且唯讀)類型加入空建構子簽名。 陣列和張成無法使用 (),因為沒有能符合它們的簽名。
未解決問題
釐清一項未解決的疑慮,來自 https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md#conclusion
with(...) 是語言中一個變化,且 [with(...)]。 在此功能之前,它指的是一個只有一個元素的集合表達式,該元素是呼叫 with-invocation-expression 的結果。 在此功能之後,它是一個集合,並會傳遞參數。
我們是否希望這種中斷只發生在使用者選擇特定語言版本時(例如 C#-14/15?)。 換句話說,如果他們用的是舊的語言版本,他們會得到之前的解析邏輯,但在新版本上則是新的解析邏輯。 還是我們 總是 希望它有較新的解析邏輯,即使是在較舊的 lang 版本上?
我們已有兩種策略的先前技術。
required例如,無論 langversion 如何,都會用新邏輯進行解析。 而,也有人會 record/field 根據語言版本調整他們的解析邏輯。
最後,這與 有重疊與影響 Dictionary Expressions,後者引入 key:value 了 KVP 元素的語法。 我們想為任何 lang 版本[with(...)]、單獨的 和 或 這類參數[with(...) : expr][expr : with(...)]建立想要的行為。