Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Note
Ez a cikk egy funkcióspecifikáció. A specifikáció a funkció tervezési dokumentumaként szolgál. Tartalmazza a specifikáció javasolt módosításait, valamint a funkció tervezése és fejlesztése során szükséges információkat. Ezeket a cikkeket mindaddig közzéteszik, amíg a javasolt specifikációmódosításokat nem véglegesítik, és be nem építik a jelenlegi ECMA-specifikációba.
A szolgáltatás specifikációja és a befejezett implementáció között eltérések lehetnek. Ezeket a különbségeket a vonatkozó nyelvi tervezési értekezlet (LDM) megjegyzései rögzítik.
A funkcióspektusok C# nyelvi szabványba való bevezetésének folyamatáról a specifikációkcímű cikkben olvashat bővebben.
A bajnokkal kapcsolatos kérdés: https://github.com/dotnet/csharplang/issues/8887
Motiváció
A szótárkifejezési funkció azt észlelte, hogy a gyűjteménykifejezéseknek a felhasználó által megadott adatok mentén kell továbbítaniuk a végső gyűjtemény viselkedésének konfigurálásához. A szótárak lehetővé teszik a felhasználók számára a kulcsok összehasonlításának testreszabását, a kulcsok közötti egyenlőség definiálását, valamint a rendezést vagy kivonatolást (rendezett vagy kivonatolt gyűjtemények esetén). Ez akkor szükséges, ha bármilyen szótártípust (például D d = new D(...), D d = D.CreateRange(...) sőt IDictionary<...> d = <synthesized dict>) hoz létre
Ennek támogatásához a rendszer egy új with(...arguments...) elemet javasol egy gyűjteménykifejezés első elemeként:
Dictionary<string, int> nameToAge = [with(comparer), .. d1, .. d2, .. d3];
- A hívásra való
new CollectionType(...)fordításkor ezek...arguments...határozzák meg a megfelelő konstruktort, és ennek megfelelően továbbítják őket. - Hívásra való
CollectionFactory.Createfordításkor a rendszer ezeket...arguments...az elemek argumentumávalReadOnlySpan<ElementType>továbbítja, amelyek mindegyike a megfelelőCreatetúlterhelés meghatározására szolgál, és ennek megfelelően továbbítja őket. - Interfészre (például
IDictionary<,>) történő fordításkor csak egyetlen argumentum engedélyezett. Implementálja az egyik jól ismert BCL összehasonlító felületet, és a végső példány szemantikáját összehasonlító kulcs szabályozására szolgál.
Ez a szintaxis lett kiválasztva:
- Az összes információ a szintaxison
[...]belül marad. Annak biztosítása, hogy a kód továbbra is egyértelműen jelezze a gyűjtemény létrehozását. - Ez nem azt jelenti, hogy konstruktort
newhív meg (ha nem így jön létre az összes gyűjtemény). - Nem jelenti a gyűjtemény értékeinek többszöri létrehozását/másolását (például egy utótagot
with { ... }). - Nem konzisztens a műveletek sorrendje, különösen a C#konzisztens balról jobb oldali kifejezés-kiértékelési sorrendjének szemantikája esetén. Például nem értékeli ki a gyűjtemény létrehozásához használt argumentumokat a gyűjtemény feltöltéséhez használt kifejezések kiértékelése után .
- Nem kényszeríti a felhasználót arra, hogy egy (potenciálisan nagy méretű) gyűjteménykifejezés végéig olvassa az olvasást az alapvető viselkedési szemantikák meghatározásához. Ha például egy százsoros szótár végére kellett néznie, csak hogy megtalálja, igen, a megfelelő kulcs-összehasonlítót használta.
- Mindkettő nem finom, ugyanakkor nem túl részletes. Az argumentumok megjelölése
;helyett például,nagyon egyszerű szintaxist kell kihagyni.with()csak 6 karaktert ad hozzá, és könnyen kiemelkedik, különösen awithkulcsszó szintaxisának színezésével. - Szépen olvas. "Ez egy gyűjteménykifejezés, amely ezeket az argumentumokat tartalmazza, és ezekből az elemekből áll."
- Megoldja a szótárak és a készletek összehasonlító szükségletét.
- Biztosítja, hogy minden felhasználónak szüksége van az argumentumok átadására, vagy hogy a jövőben az összehasonlítókon túli igényeink már kezelhetők legyenek.
- Nem ütközik meglévő kóddal (keresésre).https://grep.app/
Tervezési filozófia
Az alábbi szakasz a korábbi tervezési filozófiai megbeszéléseket ismerteti. Beleértve azt is, hogy miért utasítottak el bizonyos űrlapokat.
Ennek a felhasználó által definiált adatoknak két fő irányt adhatunk meg. Az első az, hogy csak a összehasonlító térben lévő értékeket kell speciálisan megadni (amelyeket a BCL-ek IComparer<T> vagy IEqualityComparer<T> -típusok által öröklő típusokként határozunk meg). A második egy általánosított mechanizmus biztosítása, amely tetszőleges argumentumokat biztosít a végső meghívott API-nak gyűjteménykifejezések létrehozásakor. Az elsődleges szótárkifejezés specifikációja bemutatja, hogyan lehet az előbbit elvégezni, míg ez a specifikáció az utóbbit keresi.
Az összehasonlítók megoldásainak vizsgálatai gyengeségeket tártak fel a megközelítésükben, ha tetszőleges érvekre szeretnénk kiterjeszteni őket. Például:
Elemszintaxis újrahasználása, ahogyan az űrlapon:
[StringComparer.OrdinalIgnoreCase, "mads": 21]. Ez jól működik egy olyan térben, aholKeyValuePair<,>a összehasonlítók nem örökölnek a gyakori típusoktól. De letörik egy olyan világban, ahol lehet, hogy:HashSet<object> h = [StringComparer.OrdinalIgnoreCase, "v"]. Ez egy összehasonlító mentén halad? Vagy megpróbál két objektumértéket elhelyezni a készletben?Argumentumok és finom szintaxisú elemek elválasztása (például pontosvessző helyett pontosvesszővel elválasztani őket
[comparer; v1]). Ez nagyon zavaró helyzeteket rejt magában, amikor egy felhasználó véletlenül ír[1; 2](és olyan gyűjteményt kap, amely az "1" értéket adja át, például a "kapacitás" argumentumot egyList<>, és csak a "2" egyetlen értéket tartalmazza), amikor azt tervezték[1, 2](két elemből álló gyűjtemény).
Emiatt az tetszőleges argumentumok támogatásához úgy gondoljuk, hogy nyilvánvalóbb szintaxisra van szükség az értékek egyértelműbb kijelöléséhez. Ezen a téren számos más tervezési szempont is felmerült. Bizonyos sorrendben ezek a következők:
Hogy a megoldás nem egyértelmű, és olyan kódtöréseket okoz, amelyeket a felhasználók valószínűleg a gyűjteménykifejezésekkel használnak. Például:
List<Widget> c = [new(...), w1, w2, w3];Ez ma már legális, mivel a
new(...)kifejezés egy "implicit objektum létrehozása", amely létrehoz egy új widgetet. Ezt nem tudjuk arra visszavenni, hogy argumentumokat továbbítsunk a konstruktornakList<>, mivel az biztosan megszakítaná a meglévő kódot.Hogy a szintaxis nem terjed ki a
[...]szerkezeten kívülre. Például:HashSet<string> s = [...] with ...;Ezek a szintaxisok úgy értelmezhetők, hogy a gyűjtemény először létrejön, majd újra létrejön egy eltérő formában, ami az adatok többszörös átalakítását jelenti, és potenciálisan nem kívánt magasabb költségeket eredményez (még akkor is, ha ez nem az, amit a rendszer bocsát ki).
Ez
new, mint egy potenciális kulcsszó, hogy egyáltalán ebben a térben nem kívánatos zavaró. Mindkettő azért, mert[...]már jelzi, hogy létrejön egy új objektum, és mivel a gyűjteménykifejezés fordításai nem konstruktor API-kon (például a Létrehozási metódusmintán ) keresztül mennek keresztül.Hogy a megoldás ne legyen túlzottan részletes. A gyűjteménykifejezések alapvető értékajánlata a rövidség. Tehát ha az űrlap nagy mennyiségű szintaktikai állványzatot ad hozzá, az visszalépésnek fog tűnni, és aláássa a gyűjteménykifejezések használatának értékét, szemben a meglévő API-k meghívásával a gyűjtemény létrehozásához.
Vegye figyelembe, hogy egy ilyen new([...], ...) szintaxis a fenti "2" és "3" értékre is érvényes. Úgy jelenik meg, mintha konstruktort hívnánk meg (ha nem vagyunk), és azt jelenti, hogy egy létrehozott gyűjteménykifejezést ad át a konstruktornak, ami biztosan nem.
A fentiek alapján néhány olyan lehetőség jött létre, amelyek úgy érzik, hogy megoldják az argumentumok átadásának igényeit anélkül, hogy túllépnék a gyűjteménykifejezések céljainak határait.
[with(...arguments...)] Tervezés
Syntax:
collection_element
: expression_element
| spread_element
+ | with_element
;
+with_element
+ : 'with' argument_list
+ ;
Ezzel a nyelvtani termeléssel azonnal megjelenik egy szintaktikai kétértelműség. Hasonló a kétértelműség és spread_elementexpression_element ( itt magyarázható, van egy azonnali szintaktikai kétértelműség között with_element és expression_element.
Konkrétan with(<arguments>) mindkettő pontosan a termelési törzs, with_elementés ez is elérhető keresztül expression_element -> expression -> ... -> invocation_expression. A collection_elements egyszerű átfogó szabálya van. Pontosabban, ha az elem lexikálisan a jogkivonat-sorozattal with( kezdődik, akkor a rendszer mindig úgy kezeli, mint egy with_element.
Ez kétféleképpen előnyös. Először is a fordító implementációnak csak azokat az azonnal megjelenő jogkivonatokat kell megvizsgálnia, amelyek alapján megállapíthatja, hogy milyen elemet kell elemezni. Másodszor, ennek megfelelően a felhasználó triviálisan megértheti, hogy milyen elemük van, anélkül, hogy mentálisan meg kellene próbálnia elemezni az alábbiakat, hogy lássa, kell-e úgy gondolnia rá, mint egy with_element vagy egy expression_element.
Examples
Példák a következőkre:
// 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];
Ezek a formák úgy tűnik, hogy "olvasni" ésszerűen is. Ezekben az esetekben a kód "gyűjteménykifejezést hoz létre, a következő argumentumokkal együtt" a végső példány vezérléséhez, majd a feltöltéshez használt további elemeket. Az első sor például "olyan sztringlistát hoz létre, amelynek kapacitása kétszer akkora, mint a benne elosztandó értékek száma"
Fontos, hogy ennek a kódnak kevés esélye van arra, hogy figyelmen kívül hagyják, mint például a következő űrlapok: [arg; element], miközben minimális részletességet ad hozzá, nagy rugalmassággal, hogy minden kívánt argumentumot átadjon.
Ez gyakorlatilag egy kompatibilitástörő változás lenne, ahogy with(...) az egy már meglévő, úgynevezett metódus hívása with. Az implicit típusú értékek létrehozásának new(...) és ajánlott módjával ellentétben azonban sokkal kevésbé valószínű, with(...) hogy metódusnévként futtassa a .Net-elnevezést a metódusok esetében. Abban a valószínűtlen esetben, ha egy felhasználó rendelkezik ilyen metódussal, akkor minden bizonnyal továbbra is be tudja hívni a meglévő metódust a használatával @with(...).
Ezt az elemet a with(...) következőképpen fordítanánk le:
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);
Más szóval, a argument_list argumentumokat átadjuk a megfelelő konstruktornak, ha konstruktort hívunk meg, vagy ha ilyen metódust hívunk meg, a megfelelő "létrehozási módszernek". Azt is lehetővé tenné, hogy a BCL-összehasonlító típusoktól öröklő egyetlen argumentum legyen megadva, amikor a célszótár-felület egyik típusának példányosításával szabályozni szeretné annak viselkedését.
Conversions
A gyűjteménykifejezések konverziós szakasza a következő módon frissül:
> 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.
Figyelje meg, hogy a tényleges argumentumok argument_listwith_element nem befolyásolják, hogy az átalakítás létezik-e vagy sem. Csak önmagának a jelenléte vagy hiánya with_element . Az intuíció itt egyszerűen az, hogy ha a gyűjteménykifejezést egy (például [x, y, z]) nélkül írják, akkor a konstruktort args nélkül kell meghívni. Míg ha van [with(...), x, y, z] , akkor meghívhatja a megfelelő konstruktort. Ez azt is jelenti, hogy az argumentum nélküli konstruktorral nemhívható típusok gyűjteménykifejezéssel használhatók, de csak akkor, ha a gyűjteménykifejezés tartalmaz egy with_element.
Az with_element a tényleges meghatározást adhatja meg arról, hogy egy adott eszköz hogyan befolyásolja az építkezést.
Construction
Az építés az alábbiak szerint frissül.
A gyűjteménykifejezés elemeinek kiértékelése sorrendben történik, balról jobbra. A gyűjteményargumentumokon belül az argumentumok kiértékelése sorrendben történik, balról jobbra. Az egyes elemek vagy argumentumok kiértékelése pontosan egyszer történik, és a további hivatkozások a kezdeti értékelés eredményeire vonatkoznak.
Ha collection_arguments szerepel, és nem az első elem a gyűjteménykifejezésben, a jelentés fordítási időt jelző hibát jelez.
Ha az argumentumlistadinamikus típusú értékeket tartalmaz, a rendszer fordítási időt jelző hibát jelez (LDM-2025-01-22).
Constructors
Ha a céltípus egy implementálható struktúra vagy System.Collections.IEnumerable, és a céltípus nem rendelkezik létrehozási metódussal, és a céltípus nem általános paramétertípus, akkor:
- A túlterhelés feloldása a jelöltek legjobb példánykonstruktorának meghatározására szolgál.
- A jelölt konstruktorok készlete az összes elérhető példánykonstruktor, amelyet a céltípuson deklaráltak, és amelyek az alkalmazható függvénytagban meghatározott argumentumlistára vonatkoznak.
- Ha a legjobb példánykonstruktor található, a rendszer meghívja a konstruktort az argumentumlistával.
- Ha a konstruktor rendelkezik paraméterrel
params, a meghívás kibontott formában is lehetséges.
- Ha a konstruktor rendelkezik paraméterrel
- Ellenkező esetben kötési hiba jelenik meg.
// 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 metódusok
Ha a céltípus egy létrehozási metódussal rendelkező típus, akkor:
- A túlterhelés feloldása a jelöltek legjobb létrehozási módszerének meghatározására szolgál.
- A céltípus minden létrehozási módszeréhez meghatározunk egy, a létrehozási metódussal azonos aláírású, de az utolsó paraméter nélküli vetítési metódust.
- A jelölt vetítési módszerek halmaza azokat a vetítési módszereket tartalmazza, amelyek az alkalmazható függvénytagban meghatározott argumentumlistára vonatkoznak.
- Ha a legjobb vetítési módszer található, a rendszer meghívja a megfelelő létrehozási metódust az elemeket tartalmazó argumentumlistával
ReadOnlySpan<T>. - Ellenkező esetben kötési hiba jelenik meg.
[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: Metódusok létrehozása
Olyan gyűjteménykifejezések esetében, amelyekben a céltípus definíciója attribútummal rendelkezik [CollectionBuilder] , a létrehozási metódusok a következők, amelyek agyűjteménykifejezésekből frissülnek: metódusok létrehozása.
Az
[CollectionBuilder(...)]attribútum a gyűjteménytípus egy példányának létrehozásához meghívandó metódus szerkesztőtípusát és metódusnevét adja meg.A szerkesztő típusának nem általános
classvagystruct.Először meg kell határozni az alkalmazandó létrehozási módszerek
CMkészletét. Olyan módszerekből áll, amelyek megfelelnek a következő követelményeknek:
- A metódusnak az attribútumban megadott névvel kell rendelkeznie
[CollectionBuilder(...)].- A metódust közvetlenül a szerkesztőtípuson kell definiálni.
- A metódusnak a következőnek kell lennie
static: .- A metódusnak elérhetőnek kell lennie a gyűjteménykifejezés használatakor.
- A metódus aritásának meg kell egyeznie a gyűjteménytípus aritásával .
- A metódusnak érték szerint átadott utolsó típusú
System.ReadOnlySpan<E>paraméterrel kell rendelkeznie.- Identitáskonverzió, implicit referenciakonvertálás vagy boxing átalakítás történik a metódus visszatérési típusától a gyűjteménytípusig.
Az alaptípusokon vagy interfészeken deklarált metódusok figyelmen kívül lesznek hagyva, és nem részei a
CMkészletnek.
Olyan céltípusú
C<S0, S1, …>esetében, ahol a típusdeklarációhozC<T0, T1, …>társított szerkesztőmetódusB.M<U0, U1, …>()tartozik, a céltípus általános típusargumentumait a rendszer a legbelső típustól a legbelsőig alkalmazza a szerkesztő metódusra.
A korábbi algoritmus főbb különbségei a következők:
- A létrehozási metódusok további paraméterekkel is rendelkezhetnek a paraméter
ReadOnlySpan<E>. - Több létrehozási módszer is támogatott.
Interfész céltípusa
Ha a céltípus egy felülettípus, akkor:
A túlterhelésfeloldás a legjobb jelöltmetódus-aláírás meghatározására szolgál.
A jelölt-aláírások halmaza az alábbi aláírások a célfelülethez, amelyek az alkalmazható függvénytagban meghatározott argumentumlistára vonatkoznak.
Interfaces Jelölt-aláírások IEnumerable<E>IReadOnlyCollection<E>IReadOnlyList<E>()(nincsenek paraméterek)ICollection<E>IList<E>List<E>()List<E>(int)
Ha a legjobb módszeradékot találja, a szemantikák a következők:
- A jelölt aláírása
IEnumerable<E>,IReadOnlyCollection<E>ésIReadOnlyList<E>egyszerűen(), és ugyanazt a jelentést, mintha egyáltalán nem rendelkezik azwith()elem. - A jelölt aláírások
IList<T>ICollection<T>a konstruktorok ésList<T>()a konstruktorok aláírásaiList<T>(int). Az érték létrehozásakor (lásd: Mutable Interface Translation) a rendszer meghívja a megfelelőList<T>konstruktort. - Ellenkező esetben kötési hiba jelenik meg.
Dictionary-Interface céltípus
Ez itt van megadva a szakaszban definiált https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.mdfunkció részeként.
A fenti lista a következő elemekkel bővül:
| Interfaces | Jelölt-aláírások |
|---|---|
IReadOnlyDictionary<K, V> |
() (nincsenek paraméterek)(IEqualityComparer<K>? comparer) |
IDictionary<K, V> |
Dictionary<K, V>()Dictionary<K, V>(int)Dictionary<K, V>(IEqualityComparer<K>)Dictionary<K, V>(int, IEqualityComparer<K>) |
Ha a legjobb metódusa aláírást találja, a szemantikák a következők:
- A jelölt aláírások
IReadOnlyDictionary<K, V>(()amelyek jelentése megegyezik azzal, hogy egyáltalán nem rendelkezik azwith()elemet), és(IEqualityComparer<K>). Ez az összehasonlító a megfelelő kivonatoláshoz és a fordító által létrehozott célszótár kulcsainak összehasonlításához használható (lásd : Nem mutable Interface Translation). - A jelölt aláírások a
IDictionary<T>,Dictionary<K, V>()Dictionary<K, V>(int)ésDictionary<K, V>(IEqualityComparer<K>)konstruktorok aláírásaiDictionary<K, V>(int, IEqualityComparer<K>). Az érték létrehozásakor (lásd: Mutable Interface Translation) a rendszer meghívja a megfelelőDictionary<K, V>konstruktort. - Ellenkező esetben kötési hiba jelenik meg.
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
Egyéb céltípusok
Ha a céltípus bármilyen más típus, akkor a rendszer kötési hibát jelent az argumentumlistához, még akkor is, ha üres.
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
Bírók biztonsága
A collection-expressions.md#ref-safety szabályokat úgy módosítjuk, hogy figyelembe vegyék az with() elemet.
Lásd még a 16.4.15.
Metódusok létrehozása
Ez a szakasz olyan gyűjteménykifejezésekre vonatkozik, amelyek céltípusa megfelel a CollectionBuilderAttribute metódusokban meghatározott korlátozásoknak.
A biztonságos környezet meghatározása a collection-expressions.md#ref-safety záradék módosításával történik ( a módosítások félkövér nyelven):
- Ha a céltípus egy létrehozási metódussal rendelkező refstruktúratípus, a gyűjteménykifejezés biztonságos környezete a létrehozási metódus meghívásának biztonságos környezete, ahol az argumentumok az
with()elemargumentumok, majd a gyűjteménykifejezés az utolsó paraméter (aReadOnlySpan<E>paraméter) argumentuma.
A metódusargumentumoknak meg kell egyeznie a gyűjteménykifejezésre vonatkozó korlátozással. A fenti biztonságos környezet meghatározásához hasonlóan a metódusargumentumoknak meg kell egyezniük a megszorítással, ha a gyűjteménykifejezést a létrehozási metódus meghívásaként kezelik, ahol az argumentumok az with() elemargumentumok, amelyeket a gyűjteménykifejezés követ az utolsó paraméter argumentumaként.
Konstruktorhívások
Ez a szakasz olyan gyűjteménykifejezésekre vonatkozik, amelyek céltípusa megfelel a Konstruktorokban meghatározott korlátozásoknak.
A következő űrlap ref strukturáltípusának gyűjteménykifejezéséhez:
[with(a₁, a₂, ..., aₙ), e₁, e₂, ..., eₙ]
A gyűjteménykifejezés biztonságos környezete a következő kifejezések biztonságos környezeteinek legszűkebb része :
- Objektumlétrehozó kifejezés
new C(a₁, a₂, ..., aₙ), aholCa céltípus - Az elemkifejezések
e₁, e₂, ..., eₙ(maguk a kifejezések, vagy az oldalpáros elem esetén az oldalpár értéke).
A metódusargumentumoknak meg kell egyeznie a gyűjteménykifejezésre vonatkozó korlátozással. A korlátozást úgy alkalmazza a rendszer, hogy a gyűjteménykifejezést az űrlap new C(a₁, a₂, ..., aₙ) { e₁, e₂, ..., eₙ } objektumlétrehozásaként kezeli a low-level-struct-improvements.md#rules-for-object-initializers fájlonként.
- A kifejezéselemeket úgy kezeli a rendszer, mintha gyűjteményelem-inicializálók lennének.
- Az oldalpár elemeit hasonlóan kezeli a rendszer, ha ideiglenesen feltételezi, hogy
Cvan egyAdd(SpreadType spread)metódusa, aholSpreadTypeaz oldalpár értékének típusa van.
Megválaszolt kérdések
dynamic Érvek
Engedélyezettek-e a típussal rendelkező dynamic argumentumok? Ehhez szükség lehet a futásidejű iratgyűjtő használatára a túlterhelés feloldásához, ami megnehezítené a jelöltek számának korlátozását, például a gyűjteménykészítő esetek esetében.
Felbontás: Nem engedélyezett. LDM-2025-01-22
with() kompatibilitástörő változás
A javasolt with() elem egy kompatibilitástörő változás.
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) { ... }
Ellenőrizze, hogy a kompatibilitástörő változás elfogadható-e, és hogy a kompatibilitástörő módosításnak a nyelvi verzióhoz kell-e kötődnie.
Felbontás: A korábbi nyelvi verzió összeállításakor tartsa meg a korábbi viselkedést (nem változik kompatibilitástörő változás). LDM-2025-03-17
Hatással vannak-e az argumentumok a gyűjteménykifejezések konvertálására?
A gyűjtemény argumentumainak és az alkalmazható metódusoknak befolyásolják a gyűjteménykifejezés konvertálhatóságát?
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) { ... }
Ha az argumentumok befolyásolják az átalakíthatóságot az alkalmazható módszerek alapján, az argumentumoknak valószínűleg a típusbeli következtetésre is hatással kell lennie.
Print([with(comparer: StringComparer.Ordinal)]); // Print<string>(HashSet<string>)?
Referenciaként a cél típusú new() esetekhez hasonló esetek hibákat eredményeznek.
Print<int>(new(comparer: null)); // error: ambiguous
Print(new(comparer: StringComparer.Ordinal)); // error: type arguments cannot be inferred
Felbontás: A gyűjteményargumentumokat figyelmen kívül kell hagyni a konvertálásokban és a típuskövetkeztetésben. LDM-2025-03-17
Gyűjteményszerkesztő metódus paraméterének sorrendje
A gyűjteményszerkesztő metódusok esetében a span paraméternek a gyűjteményargumentumok bármely paramétere előtt vagy után kell lennie?
Az elemek először lehetővé tennék az argumentumok opcionálisként való deklarálásához.
class MySetBuilder
{
public static MySet<T> Create<T>(ReadOnlySpan<T> items, IEqualityComparer<T> comparer = null) { ... }
}
Az argumentumok először lehetővé tennék, hogy a span paraméter params legyen, és támogassa a közvetlenül kibontott formában történő hívásokat.
var s = MySetBuilder.Create(StringComparer.Ordinal, x, y, z);
class MySetBuilder
{
public static MySet<T> Create<T>(IEqualityComparer<T> comparer, params ReadOnlySpan<T> items) { ... }
}
Felbontás: Az elemek span paraméterének kell lennie az utolsó paraméternek. LDM-2025-03-12
Argumentumok a korábbi nyelvi verzióval
Hiba jelenik with() meg egy korábbi nyelvi verzió összeállításakor, vagy with egy másik szimbólumhoz kapcsolódik a hatókörben?
Felbontás: A gyűjteménykifejezésen with belül nem változik kompatibilitástörő változás a korábbi nyelvi verziók fordításakor.
LDM-2025-03-17
Céltípusok, ahol argumentumokra van szükség
Támogatja-e a gyűjteménykifejezések konvertálását olyan céltípusokra, ahol argumentumokat kell megadni, mert az összes konstruktor vagy gyári metódus legalább egy argumentumot igényel?
Az ilyen típusok olyan gyűjteménykifejezésekkel használhatók, amelyek explicit with() argumentumokat tartalmaznak, de a típusok nem használhatók paraméterekhez params .
Vegyük például a következő, gyári módszerből létrehozott típust:
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) { ... }
}
Ugyanez a kérdés vonatkozik a konstruktor közvetlen meghívására, mint az alábbi példában.
Azoknál a céltípusoknál, ahol a konstruktort közvetlenül hívják meg, a gyűjteménykifejezés konvertálásához jelenleg argumentumok nélkül hívható konstruktorra van szükség, a gyűjtemény argumentumait azonban figyelmen kívül hagyja a rendszer az átalakíthatóság meghatározásakor.
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) { ... }
// ...
}
Felbontás: Olyan céltípusokra való konvertálás támogatása, ahol minden konstruktor vagy gyári metódus argumentumokat igényel, és az átalakításhoz szükséges with() .
LDM-2025-03-05
__arglist
Támogatni kell __arglist az elemeket with() ?
class MyCollection : IEnumerable
{
public MyCollection(__arglist) { ... }
public void Add(object o) { }
}
MyCollection c;
c = [with(__arglist())]; // ok
c = [with(__arglist(x, y)]; // ok
Felbontás: A gyűjtemény argumentumai csak __arglist akkor támogatottak, ha ingyenesek.
LDM-2025-03-05
A felülettípusok argumentumai
Támogatni kell-e az argumentumokat a felületi céltípusok esetében?
ICollection<int> c = [with(capacity: 4)];
IReadOnlyDictionary<string, int> d = [with(comparer: StringComparer.Ordinal), ..values];
A mutable interface típusok esetében a lehetőségek a következők:
- Használja a példányosításhoz szükséges jól ismert típusból származó akadálymentes konstruktorokat:
List<T>vagyDictionary<K, V>. - Használjon egyedi típustól független aláírásokat, például használjon
new()ésnew(int capacity)használjonICollection<T>ésIList<T>használjon (lásd az egyes felületek lehetséges aláírásainak felépítését ).
Az akadálymentes konstruktorok jól ismert típusból való használata a következő következményekkel jár:
- A paraméternevek (opcionális-ness)
paramsközvetlenül a paraméterekből származnak. - Minden akadálymentes konstruktor megtalálható benne, annak ellenére, hogy ez nem feltétlenül hasznos a gyűjteménykifejezésekhez, például
List(IEnumerable<T>)amelyek lehetővé tennékIList<int> list = [with(1, 2, 3)];. - A konstruktorok készlete a BCL-verziótól függhet.
Újraértelmezés: A jól ismert típusok akadálymentes konstruktorainak használata. Garantáltuk, hogy ezeket a típusokat használjuk, így ez csak "kiesik", és ez az értékek létrehozásának legtisztább és legegyszerűbb útja.
A nem mutable felülettípusok esetében a beállítások hasonlóak:
- Ne csinálj semmit. This
- Használjon adott típustól független aláírásokat, bár az egyetlen forgatókönyv a C#14 esetében lehet
new(IEqualityComparer<K> comparer)IReadOnlyDictionary<K, V>.
Az akadálymentes konstruktorok használata valamilyen jól ismert típusból (a mutable-interface-types stratégiája) nem járható út, mivel nincs kapcsolat egyetlen meglévő típussal sem, és a végső típust használhatjuk és/vagy szintetizálhatjuk. Ezért furcsa új követelményeknek kell teljesülniük ahhoz, hogy a fordító képes legyen leképezni az említett típusú meglévő konstruktorokat (még a fejlődés során is) a ténylegesen létrehozott nem mutable példányra.
Újramegjelenítés: Adott típustól független aláírásokat használjon. A C# 14 esetében pedig csak a támogatás new(IEqualityComparer<K> comparer) , IReadOnlyDictionary<K, V> mivel ez az egyetlen nem használható felület, ahol úgy érezzük, hogy a használhatóság/szemantika szempontjából kritikus fontosságú, hogy a felhasználók ezt megadják. A jövőbeli C#-kiadások megfontolhatják a készlet kibővítését a megadott megalapozott indokok alapján.
Megoldás:https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-23.md
A felületi céltípusok argumentumai támogatottak. A rendszer mind a mutable, mind a nem mutable interfészek esetében összeválogatja az argumentumokat.
A várt lista (amelyet továbbra is ldm-nek kell ratifikálni) az interfész céltípusa
Üres argumentumlisták
Engedélyeznünk kell üres argumentumlistákat néhány vagy az összes céltípushoz?
Az üres with() érték a nem with()értéknek felel meg. Lehet, hogy konzisztenciát biztosít a nem üres esetekhez, de nem ad hozzá új képességeket.
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?
Megoldás:https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-05-12.md#empty-argument-lists
Az argumentumok nélkül hívható konstruktortípusokhoz és építőtípusokhoz engedélyezzük a() lehetőséget, és üres konstruktor-aláírásokat adunk hozzá a felületi (módosítható és olvasható) típusokhoz. A tömbök és a spanok nem engedélyezik a() lehetőséget, mivel nincsenek olyan aláírások, amelyek elférnének rajtuk.
Kérdések megnyitása
Nyitott aggály véglegesítése a https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md#conclusion
with(...)a nyelv kompatibilitástörő változása a következővel: .[with(...)] A funkció előtt egy egy elemet tartalmazó gyűjteménykifejezést jelent, amely a with-invocation-expression meghívásának eredménye. A funkció után ez egy gyűjtemény, amely argumentumokat ad át neki.
Azt szeretnénk, hogy ez a törés csak akkor történjen meg, ha egy felhasználó kiválaszt egy adott nyelvi verziót (például C#-14/15?). Más szóval, ha egy régebbi langversion-on vannak, a korábbi elemzési logikát kapják, de az újabb verzióban az újabb elemzési logikát kapják. A Vagy mindig azt akarjuk, hogy az újabb elemzési logika, még egy régebbi langversion?
Mindkét stratégiához van előzetes képünk.
requiredpéldául a rendszer mindig elemzi az új logikát, a langversion-tól függetlenül. Míg mások record/field a nyelvi verziótól függően elemzik az elemzési logikát.
Végül ez átfedésben Dictionary Expressionsvan és hatással van a key:value KVP-elemek szintaxisára. Szeretnénk létrehozni a viselkedést szeretnénk minden lang verzió, és [with(...)] a saját, és a dolgok, mint [with(...) : expr] vagy [expr : with(...)].
C# feature specifications