Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Uyarı
Bu makale bir özellik belirtimidir. Belirtim, özelliğin tasarım belgesi olarak görev alır. Önerilen belirtim değişikliklerini ve özelliğin tasarımı ve geliştirilmesi sırasında gereken bilgileri içerir. Bu makaleler, önerilen belirtim değişiklikleri son haline getirilene ve geçerli ECMA belirtimine dahil edilene kadar yayımlanır.
Özellik belirtimi ile tamamlanan uygulama arasında bazı tutarsızlıklar olabilir. Bu farklılıklar ilgili dil tasarım toplantısı (LDM) notlarında yakalanır.
Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek için
Şampiyonluk sorunu: https://github.com/dotnet/csharplang/issues/8887
Motivasyon
Sözlük ifadesi özelliği, koleksiyon ifadelerinin son koleksiyonun davranışını yapılandırmak için kullanıcı tarafından belirtilen verileri geçirme gereksinimini belirledi. Özel olarak, sözlükler kullanıcıların anahtarların karşılaştırma şeklini özelleştirmesine olanak sağlar; bunları kullanarak anahtarlar arasında eşitlik tanımlamak ve sıralama veya karma oluşturma (sırasıyla sıralanmış veya karma koleksiyonlar söz konusu olduğunda). Bu gereksinim, herhangi bir tür sözlük türü (, ve hatta D d = new D(...)) D d = D.CreateRange(...)IDictionary<...> d = <synthesized dict> oluştururken geçerlidir.
Bunu desteklemek için koleksiyon ifadesinin ilk öğesi olarak yeni with(...arguments...) bir öğe önerilir:
Dictionary<string, int> nameToAge = [with(comparer), .. d1, .. d2, .. d3];
- Bir
new CollectionType(...)çağrıya çevrilirken, bunlar...arguments...uygun oluşturucuyu belirlemek için kullanılır ve uygun şekilde geçirilir. - Bir
CollectionFactory.Createçağrıya çevrilirken, bunlar...arguments...daha önce öğeler bağımsız değişkeniyleReadOnlySpan<ElementType>geçirilir ve bunların tümü uygunCreateaşırı yüklemeyi belirlemek için kullanılır ve buna göre geçirilir. - Bir arabirime (gibi
IDictionary<,>) çevrilirken yalnızca tek bir bağımsız değişkene izin verilir. İyi bilinen BCL karşılaştırıcı arabirimlerinden birini uygular ve son örneğin semantiğini karşılaştıran anahtarı denetlemek için kullanılır.
Bu söz dizimi şu şekilde seçilmiştir:
- Tüm bilgileri söz diziminde
[...]tutar. Kodun hala bir koleksiyonun oluşturulduğunu net bir şekilde gösterdiğinden emin olun. - Bir oluşturucuyu çağırmak
newanlamına gelmez (tüm koleksiyonlar böyle oluşturulmadığında). - Koleksiyonun değerlerinin birden çok kez oluşturulması/kopyalanması anlamına gelmez (bir sonek
with { ... }gibi. - Özellikle C#'nin tutarlı soldan sağa ifade değerlendirme sıralama semantiği ile işlem sırasını birleştirmez. Örneğin, koleksiyonu doldurmak için kullanılan ifadeleri değerlendirdikten sonra bir koleksiyon oluşturmak için kullanılan bağımsız değişkenleri değerlendirmez.
- Bir kullanıcıyı, temel davranışsal semantiği belirlemek için (büyük olabilecek) bir koleksiyon ifadesinin sonuna kadar okumaya zorlamaz. Örneğin, yüz satırlık sözlüğün sonuna kadar görmek, yalnızca bunu bulmak için evet, doğru anahtar karşılaştırıcıyı kullanıyordu.
- Her ikisi de ince değil, aynı zamanda aşırı ayrıntılı değil. Örneğin,
;bağımsız değişkenleri belirtmek yerine,kullanmak, gözden kaçacak çok kolay bir söz dizimi parçasıdır.with()yalnızca 6 karakter ekler ve özellikle anahtar sözcüğünwithsöz dizimi renklendirmesiyle kolayca öne çıkar. - Güzel okur. "Bu, bu öğelerden oluşan bu bağımsız değişkenlerle' bir koleksiyon ifadesidir."
- Hem sözlükler hem de kümeler için karşılaştırıcı gereksinimini çözer.
- Bağımsız değişkenleri geçirmek için herhangi bir kullanıcının gereksinimini veya gelecekte karşılaştırıcıların ötesinde sahip olduğumuz tüm ihtiyaçların zaten ele alınmasını sağlar.
- Mevcut kodlarla çakışmaz (aramak için kullanılır https://grep.app/ ).
Tasarım Felsefesi
Aşağıdaki bölümde önceki tasarım felsefesi tartışmaları yer almaktadır. Belirli formların neden reddedildiği de dahil.
Bu kullanıcı tanımlı verileri sağlamak için girebileceğimiz iki ana yol vardır. Birincisi , yalnızcakarşılaştırıcı alanında (BCL'nin IComparer<T> veya IEqualityComparer<T> türlerinden devralan türler olarak tanımladığımız) değerlerin özel durum olmasıdır. İkincisi, koleksiyon ifadeleri oluştururken çağrılan son API'ye rastgele bağımsız değişkenler sağlamak için genelleştirilmiş bir mekanizma sağlamaktır. Birincil sözlük ifadesi belirtimi, öncekini nasıl yapabileceğimizi gösterirken, bu belirtim ikincisini yapmayı arar.
Sadece karşılaştırıcıları geçmek için çözümlerin incelenmesi, bunları rastgele bağımsız değişkenlere genişletmek istiyorsak yaklaşımlarında zayıflıklar ortaya çıkardı. Örneğin:
Öğe söz dizimini yeniden kullanma, formda yaptığımız gibi:
[StringComparer.OrdinalIgnoreCase, "mads": 21]. Bu, ve karşılaştırıcılarının ortak türlerden devralmadığıKeyValuePair<,>bir alanda iyi çalışır. Ama bu, birinin yapabilecekleri bir dünyada yıkılır:HashSet<object> h = [StringComparer.OrdinalIgnoreCase, "v"]. Bu bir karşılaştırıcının yanından mı geçiyor? Veya kümeye iki nesne değeri yerleştirmeye mi çalışıyorsunuz?Bağımsız değişkenleri, ince söz dizimi olan öğelerle karşılaştırmalı olarak ayırma (örneğin, içinde virgül
[comparer; v1]yerine noktalı virgül kullanma). Bu durum, kullanıcının yanlışlıkla yazması[1; 2](ve örneğin bir için '1' bağımsız değişkenini 'kapasite' bağımsız değişkeni olarak geçen ve yalnızca tek '2' değerini içeren birList<>koleksiyon aldığı) ve ne zaman ([1, 2]iki öğeli bir koleksiyon) yazdığı çok kafa karıştırıcı durumlarla karşılaşıyor.
Bu nedenle, rastgele bağımsız değişkenleri desteklemek için, bu değerleri daha net bir şekilde ayırmak için daha belirgin bir söz dizimi gerektiğini düşünüyoruz. Bu alanda başka tasarım endişeleri de ortaya çıktı. Bunlar belirli bir sırada değil:
Çözümün belirsiz olmaması ve günümüzde kullanıcıların koleksiyon ifadeleriyle kullanma olasılığı olan kodda kesmelere neden olması. Örneğin:
List<Widget> c = [new(...), w1, w2, w3];Bu, ifadenin
new(...)yeni bir pencere öğesi oluşturan 'örtük nesne oluşturma' olduğu günümüzde yasaldır. Var olanList<>bozacağı için, bunu 'nin oluşturucusna bağımsız değişkenleri geçirmek için yeniden kullanamayız.Söz diziminin yapısının
[...]dışına genişletilmemesi. Örneğin:HashSet<string> s = [...] with ...;Bu söz dizimleri, koleksiyonun önce oluşturulduğu ve sonra farklı bir formda yeniden oluşturulduğu anlamına gelebilir; bu da verilerin birden çok dönüşümünün ve istenmeyebilecek daha yüksek maliyetlerin (ortaya çıkan bu olmasa bile) ortaya çıkarıldığını gösterir.
Bu
newalanda kullanmak için olası bir anahtar sözcük olarak istenmeyen bir kafa karıştırıcıdır. Her ikisi de[...]bir nesnenin oluşturulduğunu gösterdiğinden ve koleksiyon ifadesinin çevirileri oluşturucu olmayan API'lerden (örneğin, Create yöntemi deseni) geçebileceğinden.Çözümün aşırı ayrıntılı olmaması. Koleksiyon ifadelerinin temel değer teklifi kısadır. Bu nedenle, form büyük miktarda söz dizimi yapı iskelesi eklerse, geri adım gibi hissettirir ve koleksiyon ifadelerini kullanmanın değer teklifini, koleksiyonu yapmak için mevcut API'lere çağırmaya kıyasla alttan kesecektir.
Gibi new([...], ...) bir söz diziminin yukarıda hem '2' hem de '3' afoul çalıştırdığını unutmayın. Bir oluşturucuya çağrı yapıyormuşuz gibi görünmesini sağlar (olmayabilirken) ve oluşturulan bir koleksiyon ifadesinin bu oluşturucuya geçirildiğini gösterir; bu kesinlikle değildir.
Yukarıdakilerin tümüne dayanarak, koleksiyon ifadelerinin hedeflerinin sınırları dışına çıkmadan bağımsız değişkenleri geçirme gereksinimlerini çözmek için hissedilen birkaç seçenek ortaya çıktı.
[with(...arguments...)] Tasarım
Syntax:
collection_element
: expression_element
| spread_element
+ | with_element
;
+with_element
+ : 'with' argument_list
+ ;
Bu dil bilgisi üretimiyle hemen kullanıma sunulan söz dizimsel bir belirsizlik vardır. ile spread_element arasındaki expression_element belirsizliğe benzer şekilde (burada açıklanmıştır), ve with_elementarasında expression_element hemen söz dizimsel bir belirsizlik vardır.
Özellikle with(<arguments>) hem için with_elementtam olarak üretim gövdesidir hem de aracılığıyla expression_element -> expression -> ... -> invocation_expressionulaşılabilir. collection_elements için basit bir fazla arama kuralı vardır. Özellikle, öğe sözcük temelli olarak belirteç dizisiyle with( başlıyorsa, her zaman olarak with_elementdeğerlendirilir.
Bu, iki şekilde faydalıdır. İlk olarak, bir derleyici uygulaması yalnızca ne tür bir öğenin ayrıştırılması gerektiğini belirlemek için gördüğü hemen sonraki belirteçlere bakması gerekir. İkinci olarak, bir kullanıcı buna karşılık, bir veya olarak düşünmesi gerekip gerekmediğini görmek için zihinsel olarak ne tür bir öğeye sahip olduğunu zihinsel olarak ayrıştırmaya çalışmadan önemsiz bir with_elementexpression_elementşekilde anlayabilir.
Örnekler
Bunun nasıl görüneceğine örnek olarak şunlar verilebilir:
// 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];
Bu formlar makul ölçüde "okunuyor" gibi görünüyor. Tüm bu durumlarda, kod "son örneği denetlemek için aşağıdaki bağımsız değişkenlerle birlikte bir koleksiyon ifadesi oluşturma" ve ardından bunu doldurmak için kullanılan sonraki öğelerdir. Örneğin, ilk satır "içine yayılmak üzere olan değerlerin sayısının iki katı kapasiteye sahip 'ile' dizelerin listesini oluşturur"
Daha da önemlisi, bu kodun aşağıdaki gibi formlarda olduğu gibi göz ardı edilme şansı azdır: [arg; element], aynı zamanda istenen bağımsız değişkenleri geçirme esnekliğiyle birlikte en düşük ayrıntı düzeyini de ekler.
Bu teknik olarak, adlı with(...)önceden var olan bir yönteme yapılan bir çağrı olabileceği için hataya neden olan bir değişiklik with olacaktır. Ancak, örtük olarak türlenmiş değerler oluşturmanın new(...) ve önerilen bir yolu olan yöntem adından farklı olarak, with(...) yöntemler için .Net adlandırma afoul'u çalıştırma olasılığı çok daha düşüktür. Bir kullanıcının böyle bir yöntemi olması olası olmayan bir durumda, kullanarak @with(...)mevcut yöntemi çağırmaya kesinlikle devam edebilecektir.
Bu öğeyi with(...) şöyle çeviririz:
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);
Başka bir deyişle, bir oluşturucu çağırırsak argument_list bağımsız değişkenleri uygun oluşturucuya veya böyle bir yöntemi çağırırsak uygun 'create yöntemine' geçirilir. Ayrıca, davranışını denetlemek için hedef sözlük arabirim türlerinden birinin örneğini oluştururken BCL karşılaştırıcı türlerinden devralan tek bir bağımsız değişkenin sağlanmasına izin veririz.
Conversions
Koleksiyon ifadeleri için dönüştürmeler bölümü aşağıdaki şekilde güncelleştirilir:
> 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.
içindeki argument_list gerçek bağımsız değişkenlerin with_element dönüştürmenin mevcut olup olmadığını etkilemediğini unutmayın. Sadece kendisinin varlığı veya yokluğu with_element . Buradaki sezgi, koleksiyon ifadesi bir (gibi [x, y, z]) olmadan yazılırsa oluşturucuyu args olmadan çağırabilmesi gerekir. Varsa [with(...), x, y, z] uygun oluşturucuyu çağırabilir. Bu aynı zamanda bağımsız değişken içermeyen bir oluşturucuyla çağrılamayacak türlerin bir koleksiyon ifadesiyle birlikte kullanılabileceğini , ancak yalnızca öğesini içeren with_elementkoleksiyon ifadesinin kullanılabildiği anlamına gelir.
Bir inşaatı nasıl with_element etkileyeceğinin gerçek belirlenmesi aşağıda verilmiştir.
İnşaat
İnşaat aşağıdaki gibi güncelleştirilir.
Koleksiyon ifadesinin öğeleri soldan sağa sırayla değerlendirilir. Koleksiyon bağımsız değişkenlerinde bağımsız değişkenler soldan sağa sırayla değerlendirilir. Her öğe veya bağımsız değişken tam olarak bir kez değerlendirilir ve diğer başvurular bu ilk değerlendirmenin sonuçlarına başvurur.
collection_arguments dahil edilirse ve koleksiyon ifadesindeki ilk öğe değilse, derleme zamanı hatası bildirilir.
Bağımsız değişken listesindedinamik türe sahip değerler varsa, derleme zamanı hatası bildirilir (LDM-2025-01-22).
Kurucular
Hedef türü uygulayan bir yapı veya System.Collections.IEnumerable ve hedef türün oluşturma yöntemi yoksa ve hedef türü genel bir parametre türü değilse:
- Aşırı yükleme çözümlemesi , adaylardan en iyi örnek oluşturucuyu belirlemek için kullanılır.
- Aday oluşturucu kümesi, ilgili işlev üyesinde tanımlandığı gibi bağımsız değişken listesiyle ilgili olarak geçerli olan hedef türde bildirilen tüm erişilebilir örnek oluşturucularıdır.
- En iyi örnek oluşturucu bulunursa, oluşturucu bağımsız değişken listesiyle çağrılır.
- Oluşturucunun bir
paramsparametresi varsa, çağrı genişletilmiş biçimde olabilir.
- Oluşturucunun bir
- Aksi takdirde bağlama hatası bildirilir.
// 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 yöntemleri
Hedef türü oluşturma yöntemine sahip bir türse:
- Aşırı yükleme çözümlemesi , adaylardan en iyi oluşturma yöntemini belirlemek için kullanılır.
- Hedef türü için her oluşturma yöntemi için, oluşturma yöntemiyle aynı imzaya sahip ancak son parametresi olmayan bir projeksiyon yöntemi tanımlarız.
- Aday projeksiyon yöntemleri kümesi, ilgili işlev üyesinde tanımlandığı gibi bağımsız değişken listesiyle ilgili olarak geçerli olan projeksiyon yöntemleridir.
- En iyi projeksiyon yöntemi bulunursa, ilgili oluşturma yöntemi, öğeleri içeren bir bağımsız değişken listesi eklenmiş olarak
ReadOnlySpan<T>çağrılır. - Aksi takdirde bağlama hatası bildirilir.
[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: Metot oluşturma
Hedef tür tanımının özniteliğinin bulunduğu bir [CollectionBuilder] koleksiyon ifadesi için oluşturma yöntemleri şunlardır: koleksiyon ifadelerinden güncelleştirilir: create methods.
[CollectionBuilder(...)]Öznitelik, koleksiyon türünün bir örneğini oluşturmak için çağrılacak yöntemin oluşturucu türünü ve yöntem adını belirtir.oluşturucu türü genel olmayan bir
classveyastructolmalıdır.İlk olarak, oluşturma yöntemleri kümesi belirlenir. Aşağıdaki gereksinimleri karşılayan yöntemlerden oluşur:
- Metot,
[CollectionBuilder(...)]özniteliğinde belirtilen isme sahip olmalıdır.- Yöntem, doğrudan yapıcı türü üzerinde tanımlanmalıdır.
- yöntemi
staticolmalıdır.- Yöntemin, koleksiyon ifadesinin kullanıldığı yerde erişilebilir olması gerekir.
- Yöntemin aritikliği, koleksiyon türünün aritikliği ile eşleşmelidir.
- yöntemi, değerine göre geçirilen türünde
System.ReadOnlySpan<E>parametreye sahip olmalıdır.- kimlik dönüştürmesi, örtük başvuru dönüştürmesi veya kutulama dönüştürme türünden koleksiyon türüne yöntem dönüşü vardır.
Temel türler veya arabirimler üzerinde bildirilen yöntemler yoksayılır ve
CMkümesinin parçası değildir.
için, hedef türü olan bir koleksiyon ifadesinde, tür bildirimi
C<S0, S1, …>C<T0, T1, …>ilişkili bir oluşturucu yöntemiB.M<U0, U1, …>()'ye sahipse, hedef türden gelen genel tür bağımsız değişkenleri () sırasıyla ve en dış kapsayıcı türden en içe doğru bu oluşturucu yöntemine uygulanır.
Önceki algoritmadan önemli farklar şunlardır:
- Oluşturma yöntemlerinin parametresinden
ReadOnlySpan<E>önce ek parametreleri olabilir. - Birden çok oluşturma yöntemi desteklenir.
Arabirim hedef türü
Hedef tür bir arabirim türüyse:
Aşırı yükleme çözümü , en iyi aday yöntem imzasını belirlemek için kullanılır.
Aday imzalar kümesi, ilgili işlev üyesinde tanımlandığı gibi bağımsız değişken listesiyle ilgili olarak geçerli olan hedef arabirim için aşağıdaki imzalardır.
Interfaces Aday imzaları IEnumerable<E>IReadOnlyCollection<E>IReadOnlyList<E>()(parametre yok)ICollection<E>IList<E>List<E>()List<E>(int)
En iyi yöntem imzası bulunursa semantik aşağıdaki gibidir:
- ve için
IEnumerable<E>IReadOnlyCollection<E>IReadOnlyList<E>aday imzası basit()ve öğesinin olmamasıylawith()aynı anlama sahiptir. - ve için
IList<T>aday imzaları veICollection<T>List<T>()oluşturucularınınList<T>(int)imzalarıdır. Değeri oluştururken (bkz . Mutable Interface Translation), ilgiliList<T>oluşturucu çağrılır. - Aksi takdirde bağlama hatası bildirilir.
hedef türü Dictionary-Interface
Bu, burada içinde https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.mdtanımlanan özelliğin bir parçası olarak belirtilir.
Yukarıdaki liste, aşağıdaki öğelere sahip olacak şekilde genişletilmiştir:
| Interfaces | Aday imzaları |
|---|---|
IReadOnlyDictionary<K, V> |
() (parametre yok)(IEqualityComparer<K>? comparer) |
IDictionary<K, V> |
Dictionary<K, V>()Dictionary<K, V>(int)Dictionary<K, V>(IEqualityComparer<K>)Dictionary<K, V>(int, IEqualityComparer<K>) |
En iyi yöntem imzası bulunursa, semantik aşağıdaki gibidir:
- için
IReadOnlyDictionary<K, V>aday imzaları şunlardır()(öğeye hiç sahip olmamasıylawith()aynı anlama gelir) ve(IEqualityComparer<K>). Bu karşılaştırıcı, derleyicinin oluşturmayı seçtiği hedef sözlükteki anahtarları uygun şekilde karma hale getirmek ve karşılaştırmak için kullanılır (bkz . Değiştirilebilir Arabirim Çevirisi Olmayan). - için
IDictionary<T>aday imzaları ,Dictionary<K, V>()Dictionary<K, V>(int)veDictionary<K, V>(IEqualityComparer<K>)oluşturucularınınDictionary<K, V>(int, IEqualityComparer<K>)imzalarıdır. Değeri oluştururken (bkz . Mutable Interface Translation), ilgiliDictionary<K, V>oluşturucu çağrılır. - Aksi takdirde bağlama hatası bildirilir.
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
Diğer hedef türleri
Hedef türü başka bir türse, boş olsa bile bağımsız değişken listesi için bağlama hatası bildirilir.
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
Başvuru güvenliği
öğeyi hesaba eklemek için with() kurallarını ayarlarız.
Ayrıca bkz . §16.4.15 Güvenli bağlam kısıtlaması.
Yöntem oluşturma
Bu bölüm, hedef türü CollectionBuilderAttribute yöntemlerinde tanımlanan kısıtlamaları karşılayan koleksiyon ifadeleri için geçerlidir.
Güvenli bağlam, collection-expressions.md#ref-safety 'den bir yan tümce değiştirilerek belirlenir (kalın olarak değişir):
- Hedef tür oluşturma yöntemine sahip bir başvuru yapısı türüyse, koleksiyon ifadesinin güvenli bağlamı oluşturma yönteminin güvenli bağlamıdır; burada bağımsız değişkenler öğe bağımsız değişkenleridir
with()ve ardından koleksiyon ifadesi son parametrenin bağımsız değişkenidir (ReadOnlySpan<E>parametre).
Yöntem bağımsız değişkenlerinin kısıtlamayla eşleşmesi gerekir, koleksiyon ifadesi için geçerlidir. Yukarıdaki güvenli bağlam belirlemeye benzer şekilde, yöntem bağımsız değişkenleri kısıtlamayla eşleşmelidir ; burada bağımsız değişkenler, son parametre için bağımsız değişken olarak koleksiyon ifadesinin with() ardından öğe bağımsız değişkenleri olduğu create yönteminin çağrılıması olarak değerlendirilir.
Oluşturucu çağrıları
Bu bölüm, hedef türü Oluşturucular'da tanımlanan kısıtlamaları karşılayan koleksiyon ifadeleri için geçerlidir.
Aşağıdaki formun başvuru yapısı türünün koleksiyon ifadesi için:
[with(a₁, a₂, ..., aₙ), e₁, e₂, ..., eₙ]
Koleksiyon ifadesinin güvenli bağlamı , aşağıdaki ifadelerin güvenli bağlamlarının en darıdır:
- Nesne oluşturma ifadesi
new C(a₁, a₂, ..., aₙ), buradaChedef türdür - Öğe ifadeleri
e₁, e₂, ..., eₙ(ifadelerin kendileri veya bir spread öğesi söz konusu olduğunda yayılma değeri).
Yöntem bağımsız değişkenlerinin kısıtlamayla eşleşmesi gerekir, koleksiyon ifadesi için geçerlidir. Kısıtlama, koleksiyon ifadesi new C(a₁, a₂, ..., aₙ) { e₁, e₂, ..., eₙ } başına formun nesne oluşturması olarak değerlendirilerek uygulanır.
- İfade öğeleri koleksiyon öğesi başlatıcıları gibi değerlendirilir.
- Yayma öğeleri, geçici olarak bir
Cyöntemi olduğuAdd(SpreadType spread)varsayılarak benzer şekilde işlenir ve buradaSpreadTypeyayılma değerinin türüdür.
Yanıtlı sorular
dynamic Bağımsız değişken
Türü olan dynamic bağımsız değişkenlere izin verilsin mi? Bu, aşırı yükleme çözümlemesi için çalışma zamanı bağlayıcısının kullanılmasını gerektirebilir ve bu da örneğin koleksiyon oluşturucusu örnekleri için aday kümesini sınırlamayı zorlaştırabilir.
Çözünürlük: Izin verilme -yen. LDM-2025-01-22
with() hataya neden olan değişiklik
Önerilen with() öğe, hataya neden olan bir değişikliktir.
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) { ... }
Hataya neden olan değişikliğin kabul edilebilir olduğunu ve hataya neden olan değişikliğin dil sürümüne bağlı olup olmadığını onaylayın.
Çözünürlük: Önceki dil sürümüyle derleme yaparken önceki davranışı koruyun (hataya neden olan değişiklik yok). LDM-2025-03-17
Bağımsız değişkenler koleksiyon ifadesi dönüştürmeyi etkilemeli mi?
Koleksiyon bağımsız değişkenleri ve geçerli yöntemler koleksiyon ifadesinin dönüştürülebilirliğini etkilemeli mi?
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) { ... }
Bağımsız değişkenler uygulanabilir yöntemlere göre dönüştürülebilirliği etkiliyorsa, bağımsız değişkenler büyük olasılıkla tür çıkarımı da etkilemelidir.
Print([with(comparer: StringComparer.Ordinal)]); // Print<string>(HashSet<string>)?
Başvuru için, hedef türü belirtilmiş benzer durumlar hatalarla sonuçlanır new() .
Print<int>(new(comparer: null)); // error: ambiguous
Print(new(comparer: StringComparer.Ordinal)); // error: type arguments cannot be inferred
Çözünürlük: Dönüştürmelerde ve tür çıkarımında koleksiyon bağımsız değişkenleri yoksayılmalıdır. LDM-2025-03-17
Koleksiyon oluşturucu yöntemi parametre sırası
Koleksiyon oluşturucusu yöntemleri için span parametresi koleksiyon bağımsız değişkenleri için herhangi bir parametreden önce mi yoksa sonra mı olmalıdır?
Önce öğeler bağımsız değişkenlerin isteğe bağlı olarak bildirilmesine izin verir.
class MySetBuilder
{
public static MySet<T> Create<T>(ReadOnlySpan<T> items, IEqualityComparer<T> comparer = null) { ... }
}
İlk olarak bağımsız değişkenler, doğrudan genişletilmiş biçimde çağrıyı desteklemek için yayılma alanının bir params parametre olmasına izin verir.
var s = MySetBuilder.Create(StringComparer.Ordinal, x, y, z);
class MySetBuilder
{
public static MySet<T> Create<T>(IEqualityComparer<T> comparer, params ReadOnlySpan<T> items) { ... }
}
Çözünürlük: Öğelerin span parametresi son parametre olmalıdır. LDM-2025-03-12
Önceki dil sürümüne sahip bağımsız değişkenler
Önceki bir dil sürümüyle derlenirken hata bildiriliyor with() mu yoksa kapsamdaki başka bir simgeye bağlanıyor with mu?
Çözünürlük: Önceki dil sürümleriyle derlenirken koleksiyon ifadesinin içinde hataya neden olan bir değişiklik with yoktur.
LDM-2025-03-17
Bağımsız değişkenlerin gerekli olduğu hedef türler
Tüm oluşturucular veya fabrika yöntemleri en az bir bağımsız değişken gerektirdiğinden, bağımsız değişkenlerin sağlanması gereken hedef türler için koleksiyon ifadesi dönüştürmeleri desteklenmeli mi?
Bu tür türler, açık with() bağımsız değişkenler içeren koleksiyon ifadeleriyle kullanılabilir, ancak türler parametreler için params kullanılamaz.
Örneğin, bir fabrika yönteminden oluşturulan aşağıdaki türü göz önünde bulundurun:
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) { ... }
}
Oluşturucu aşağıdaki örnekte olduğu gibi doğrudan çağrıldığında da aynı soru geçerlidir.
Ancak, oluşturucunun doğrudan çağrıldığı hedef türler için, koleksiyon ifadesi dönüştürmesi şu anda bağımsız değişken olmadan çağrılabilir bir oluşturucu gerektirir, ancak dönüştürülebilirlik belirlenirken koleksiyon bağımsız değişkenleri yoksayılır.
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) { ... }
// ...
}
Çözünürlük: Tüm oluşturucuların veya fabrika yöntemlerinin bağımsız değişken gerektirdiği ve with() dönüştürme gerektirdiği hedef türlere dönüştürmeleri destekler.
LDM-2025-03-05
__arglist
Öğelerde __arglist desteklenmeli miwith()?
class MyCollection : IEnumerable
{
public MyCollection(__arglist) { ... }
public void Add(object o) { }
}
MyCollection c;
c = [with(__arglist())]; // ok
c = [with(__arglist(x, y)]; // ok
Çözünürlük: Ücretsiz olmadığı sürece koleksiyon bağımsız değişkenlerinde desteği __arglist yoktur.
LDM-2025-03-05
Arabirim türleri için bağımsız değişkenler
Arabirim hedef türleri için bağımsız değişkenler desteklenmeli mi?
ICollection<int> c = [with(capacity: 4)];
IReadOnlyDictionary<string, int> d = [with(comparer: StringComparer.Ordinal), ..values];
Değiştirilebilir arabirim türleri için seçenekler şunlardır:
- Örnek oluşturmak için gereken iyi bilinen türden erişilebilir oluşturucuları kullanın:
List<T>veyaDictionary<K, V>. - ve kullanımı gibi
new()new(int capacity)ICollection<T>IList<T>belirli türden bağımsız imzalar kullanın (bkz. Her arabirim için olası imzalar için oluşturma).
İyi bilinen bir türdeki erişilebilir oluşturucuların kullanılması aşağıdaki etkilere neden olabilir:
- parametre adları, isteğe bağlı-ness,
paramsparametrelerinden doğrudan alınır. - Tüm erişilebilir oluşturucular dahil edilir, ancak bu, örneğin izin veren
List(IEnumerable<T>)koleksiyon ifadeleriIList<int> list = [with(1, 2, 3)];için yararlı olmayabilir. - Oluşturucu kümesi BCL sürümüne bağlı olabilir.
Recomendation: İyi bilinen türlerden erişilebilir oluşturucuları kullanın. Bu türleri kullanacağımızı garanti ettik, bu nedenle bu yalnızca 'ortaya çıkıyor' ve bu değerleri oluşturmanın en açık ve en basit yoludur.
Değiştirilebilir olmayan arabirim türleri için seçenekler benzerdir:
- Hiçbir şey yapmamak. Bu
- Tek senaryo C#14 için
new(IEqualityComparer<K> comparer)olsaIReadOnlyDictionary<K, V>da, belirli türden bağımsız imzalar kullanın..
Belirli bir mevcut türle ve ve/veya sentezleyebileceğimiz son türle ilgili bir ilişki olmadığından, iyi bilinen bir türdeki erişilebilir oluşturucuları (değiştirilebilir arabirim türleri stratejisi) kullanmak uygun değildir. Bu nedenle, derleyicinin söz konusu türdeki mevcut oluşturucuları (geliştikçe bile) gerçekten oluşturduğu değiştirilemez örnekle eşleyebilmesi için tek ve yeni gereksinimler olması gerekir.
Yeniden kullanma: Belirli bir türden bağımsız imzalar kullanın. Ayrıca, C# 14 için, kullanıcıların bunu sağlamasına izin vermek için new(IEqualityComparer<K> comparer) kullanılabilirlik/semantik açısından kritik olduğunu hissettiğimiz tek değiştirilemez arabirim olduğu için yalnızca bunu destekleyinIReadOnlyDictionary<K, V>. Gelecekteki C# sürümleri, sağlanan sağlam gerekçelere göre bu kümeyi genişletmeyi göz önünde bulundurabilir.
Çözüm:https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-23.md
Arabirim hedef türleri için bağımsız değişkenler desteklenir. Hem değiştirilebilir hem de değiştirilebilir olmayan arabirimler için bağımsız değişken kümesi seçilmiş olacaktır.
Beklenen liste (yine de LDM'nin onaylanması gerekiyor) Arabirim hedef türü
Boş bağımsız değişken listeleri
Hedef türlerin bazıları veya tümü için boş bağımsız değişken listelerine izin vermeli miyiz?
Boş with() değer, hayır with()ile eşdeğer olacaktır. Boş olmayan durumlarda biraz tutarlılık sağlayabilir, ancak yeni bir özellik eklemez.
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?
Çözüm:https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-05-12.md#empty-argument-lists
Bağımsız değişken olmadan çağrılabilen oluşturucu türleri ve oluşturucu türleri için with() izni ekleyerek arabirim (mutable ve readonly) türleri için boş oluşturucu imzaları ekleyeceğiz. Diziler ve span'lar ile() izin vermez, ancak bunlara uyan imzalar yoktur.
Açık sorular
Açık bir sorunu sonlandırma https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md#conclusion
with(...) ile dilinde hataya neden olan bir değişikliktir [with(...)]. Bu özellik öncesinde, tek öğeli bir koleksiyon ifadesi anlamına gelir ve bu da -invocation-expression çağrısının withsonucudur. Bu özelliğin ardından, bağımsız değişkenlerin geçirildiği bir koleksiyondur.
Bu kesmenin yalnızca bir kullanıcı belirli bir dil sürümünü (?) C#-14/15seçtiğinde gerçekleşmesini istiyor muz? Başka bir deyişle, eski bir langversion üzerindeyse, önceki ayrıştırma mantığını alır, ancak yeni sürümde daha yeni ayrıştırma mantığını alır. Veya içinde, eski bir langversion üzerinde bile her zaman daha yeni ayrıştırma mantığına sahip olmasını mı istiyoruz?
Her iki strateji için de önceki sanat eserlerimiz var.
requiredörneğin, langversion ne olursa olsun her zaman yeni mantıkla ayrıştırılır. Öte yandan ve diğerleri dil record/field sürümüne bağlı olarak ayrıştırma mantığını değiştirir.
Son olarak, KVP Dictionary Expressionsöğelerinin söz dizimini key:value tanıtır. Herhangi bir lang sürümü için, kendi başına ve veya [with(...)]gibi [with(...) : expr] şeyler için [expr : with(...)] istediğimiz davranışı oluşturmak istiyoruz.
C# feature specifications