Megosztás a következőn keresztül:


Részleges tulajdonságok

Jegyzet

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.

Bajnoki hiba: https://github.com/dotnet/csharplang/issues/6420

Nyelvtan

A property_declaration nyelvtan (§14.7.1) a következőképpen frissül:

property_declaration
-    : attributes? property_modifier* type member_name property_body
+    : attributes? property_modifier* 'partial'? type member_name property_body
    ;  

megjegyzések: Ez némileg hasonlít a method_header(15.6.1. §) és class_declaration(15.2.1. §) megadásához. (Vegye figyelembe, hogy 946-os probléma a rendezési követelmény lazítását javasolja, és valószínűleg minden olyan deklarációra vonatkozik, amely lehetővé teszi a partial módosító számára. A közeljövőben meg szeretnénk határozni egy ilyen rendezési lazítást, és ugyanabban a kiadásban implementáljuk, amelyet ez a funkció implementál.)

Deklarációk meghatározása és megvalósítása

Ha egy tulajdonságdeklaráció részleges módosítót tartalmaz, azt mondjuk, hogy a tulajdonság részleges tulajdonság. Részleges tulajdonságok csak részleges típusok tagjaiként deklarálhatók.

A részleges tulajdonság deklarációt meghatározó deklarációnak tekintjük, amikor az accessorai pontosvesszővel zárulnak, és hiányzik az extern módosító. Ellenkező esetben ez egy végrehajtási deklaráció.

partial class C
{
    // Defining declaration
    public partial string Prop { get; set; }

    // Implementing declaration
    public partial string Prop { get => field; set => field = value; }
}

Mivel a szintaktikai űrlapot pontosvesszővel egészítettük ki a deklarálási, a részleges tulajdonság nem automatikusan implementálható. Ezért automatikusan implementált tulajdonságokat (15.7.4.§) az alábbiak szerint módosítjuk:

Az automatikusan implementált tulajdonság (röviden automatikus tulajdonság) nem absztrakt, nem extern, nem részleges, nem ref-értékű tulajdonság, és a hozzáférők esetében csak pontosvessző szerepel.

megjegyzések. Hasznos lehet, ha a fordító önállóan vizsgál egy deklarációt, és tudja, hogy meghatározó vagy végrehajtási deklarációról van-e szó. Ezért nem szeretnénk engedélyezni az automatikus tulajdonságokat két azonos partial tulajdonságdeklarációval, például. Úgy gondoljuk, hogy a funkció használati esetei nem magukban foglalják a részleges tulajdonság automatikus tulajdonsággal való implementálását, de ha triviális megvalósításra van szükség, úgy gondoljuk, hogy a field kulcsszó elég egyszerűvé teszi a dolgokat.


A részleges tulajdonságnak kell rendelkeznie egy meghatározó deklarációval és egy megvalósító deklarációval.

megjegyzések. Azt sem tartjuk hasznosnak, ha lehetővé tesszük a deklaráció két résznél több részre való felosztását, hogy lehetővé tegyük például a különböző tartozékok különböző helyeken való megvalósítását. Ezért egyszerűen csak utánozzuk a részleges módszerekkel létrehozott rendszert.


A keresésben csak egy részleges tulajdonság meghatározó deklarációja vesz részt, hasonlóan ahhoz, ahogyan csak egy részleges módszer definiáló deklarációja vesz részt a túlterhelés feloldásában.

megjegyzések. A fordítóban azt várnánk, hogy a taglistában csak a meghatározó deklaráció szimbóluma jelenik meg, a megvalósító rész szimbóluma pedig a meghatározó szimbólumon keresztül érhető el. Egyes funkciók, például a null értékű elemzések azonban keresztül a implementálási deklarációig, hogy hasznosabb működést biztosítsanak.

partial class C
{
    public partial string Prop { get; set; }
    public partial string Prop { get => field; set => field = value; }

    public C() // warning CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
    {
    }
}

A részleges tulajdonság nem rendelkezhet abstract módosítóval.

A részleges tulajdonság nem tudja explicit módon implementálni az interfésztulajdonságokat.

Attribútumok egyesítése

A részleges metódusokhoz hasonlóan az eredményül kapott tulajdonság attribútumai a részek kombinált attribútumai, amelyek meghatározatlan sorrendben vannak összefűzve, és az ismétlődések nem törlődnek.

Hívóinformációs attribútumok

Mi a szabványalapján a következő nyelvet módosítjuk:

Hiba, ha ugyanaz a hívóinformáció attribútum található egy részleges metódus definiáló és implementáló részének paraméterén, atag deklarációjában. A rendszer csak a definiáló rész hívóinformációs attribútumait alkalmazza, míg a csak a megvalósító részben előforduló hívó-info attribútumokat a rendszer figyelmen kívül hagyja.

  • A leírt hiba azon attribútumok definícióiból származik, amelyek nem rendelkeznek AllowMultiple = true. Ha többször használja őket, beleértve a részleges deklarációkat is, hibát eredményez.
  • Ha egy részleges metódus implementálási részében a hívó-info attribútumok egy paraméterre vannak alkalmazva, a Roslyn fordító figyelmeztetést jelent. Emellett figyelmeztetést is fog jelenteni egy részleges tulajdonság ugyanazon forgatókönyvére vonatkozóan.

Egyező aláírások

A 2020. . szeptember 14-i LDM-értekezlet egy sor "szigorú" követelményt határozott meg a részleges metódusok aláírás-egyeztetésére, amelyeket egy figyelmeztetési hullámban vezettek be. A részleges tulajdonságok a lehető legnagyobb mértékben hasonló követelményekkel bírnak a részleges metódusok aláírásának egyeztetéséhez, azzal a kivétellel, hogy az eltérés összes diagnosztikáját alapértelmezés szerint jelentik, és nem rejtik el figyelmeztetési hullám mögé.

Az aláírás-egyeztetési követelmények a következők:

  1. A futásidő szempontjából jelentős részleges tulajdonságdeklarációk típus- és referenciaszerű eltérései fordítási idejű hibát okoznak.
  2. A részleges tulajdonságdeklarációkban a tuppel elemnevek különbségei fordítási hibát eredményeznek, ugyanúgy, mint a részleges metódusok esetében.
  3. A tulajdonságdeklarációknak és a kiegészítő deklarációknak ugyanazokkal a módosítókkal kell rendelkezniük, bár a módosítók más sorrendben jelenhetnek meg.
    • Kivétel: ez nem vonatkozik a extern módosítóra, amely csak végrehajtási deklarációbanjelenhet meg.
  4. A részleges tulajdonságdeklarációk aláírásának minden egyéb szintaktikai különbsége fordítási időt jelző figyelmeztetést eredményez, az alábbi kivételekkel:
    • A részleges tulajdonságdeklarációk attribútumlistáinak nem kell egyeznie. Ehelyett a megfelelő pozíciókban lévő attribútumokat egyesítik az attribútumok egyesítésénekmegfelelően.
    • A null értékű környezeti különbségek nem okoznak figyelmeztetést. Más szóval az a különbség, hogy az egyik típus nullable-oblivious, a másik típus pedig nullable-annotated vagy not-nullable-annotated, nem eredményez figyelmeztetést.
    • Az alapértelmezett paraméterértéknek nem kell egyeznie. Figyelmeztetést jelent, ha egy részleges indexelő implementációs része alapértelmezett paraméterértékekkel rendelkezik. Ez hasonló egy meglévő figyelmeztetéshez, amely akkor fordul elő, ha egy részleges metódus implementálási része alapértelmezett paraméterértékekkel rendelkezik.
  5. Figyelmeztetés akkor fordul elő, ha a paraméternevek különböznek a deklarációk definiálása és megvalósítása között. A definíciórész paraméterneveit a rendszer a használati helyeken és a kibocsátó helyeken használja.
  6. Az olyan nullabilitási különbségek, amelyek nem járnak a feledésbe vonással, figyelmeztetéseket eredményeznek. A hozzáférő törzs elemzésekor a megvalósítás rész aláírását használják. A definíció rész aláírása a használati helyek elemzésekor és a kibocsátás során használatos. Ez egybeesik a részleges módszerekkel.
partial class C1
{
    public partial string Prop { get; private set; }

    // Error: accessor modifier mismatch in 'set' accessor of 'Prop'
    public partial string Prop { get => field; set => field = value; }
}

partial class C2
{
    public partial string Prop { get; init; }

    // Error: implementation of 'Prop' must have an 'init' accessor to match definition
    public partial string Prop { get => field; set => field = value; }
}

partial class C3
{
    public partial string Prop { get; }

    // Error: implementation of 'Prop' cannot have a 'set' accessor because the definition does not have a 'set' accessor.
    public partial string Prop { get => field; set => field = value; }
}

partial class C4
{
    public partial string this[string s = "a"] { get; set; }
    public partial string this[string s] { get => s; set { } } // ok

    public partial string this[int i, string s = "a"] { get; set; }
    public partial string this[int i, string s = "a"] { get => s; set { } } // CS1066: The default value specified for parameter 's' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments
}

Dokumentációs megjegyzések

Azt szeretnénk, hogy a részleges tulajdonságokra vonatkozó dokumentumbejegyzések viselkedése összhangban legyen a részleges metódusokhoz szállítottakkal. Ezt a viselkedést a https://github.com/dotnet/csharplang/issues/5193részletezi.

A részleges tulajdonság definíciójára vagy implementálási részére vonatkozó dokumentummegjegyzések is belefoglalhatók. (Vegye figyelembe, hogy a dokumentum-megjegyzések nem támogatottak a tulajdonság hozzáférőinél.)

Ha a dokumentum megjegyzései csak a tulajdonság egyik részén találhatók, ezek a dokumentum-megjegyzések a szokásos módon lesznek használva (ISymbol.GetDocumentationCommentXml()keresztül jelennek meg, a dokumentáció XML-fájlba írva stb.).

Ha a dokumentum megjegyzései mindkét részre megjelennek, a program elveti a definíciórészhez fűzött összes dokumentum-megjegyzést, és csak a megvalósítási rész dokumentum-megjegyzéseit használja.

Például a következő program:

/// <summary>
/// My type
/// </summary>
partial class C
{
    /// <summary>Definition part comment</summary>
    /// <returns>Return value comment</returns>
    public partial int Prop { get; set; }
    
    /// <summary>Implementation part comment</summary>
    public partial int Prop { get => 1; set { } }
}

Az eredmények a következő XML-dokumentációs fájlban találhatóak:

<?xml version="1.0"?>
<doc>
    <assembly>
        <name>ConsoleApp1</name>
    </assembly>
    <members>
        <member name="T:C">
            <summary>
            My type
            </summary>
        </member>
        <member name="P:C.Prop">
            <summary>
            Implementation part comment
            </summary>
        </member>
    </members>
</doc>

Ha a paraméternevek különböznek a részleges deklarációk között, <paramref> elemek a forráskód dokumentációs megjegyzéséhez társított deklaráció paraméterneveit használják. Egy implementációs deklarációhoz fűzött dokumentum megjegyzésének paramref értéke például a végrehajtási deklaráció paraméterszimbólumára hivatkozik a paraméternevükkel. Ez egybeesik a részleges módszerekkel.

/// <summary>
/// My type
/// </summary>
partial class C
{
    public partial int this[int x] { get; set; }

    /// <summary>
    /// <paramref name="x"/> // warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'x', but there is no parameter by that name
    /// <paramref name="y"/> // ok. 'Go To Definition' will go to 'int y'.
    /// </summary>
    public partial int this[int y] { get => 1; set { } } // warning CS9256: Partial property declarations 'int C.this[int x]' and 'int C.this[int y]' have signature differences.
}

Az eredmények a következő XML-dokumentációs fájlban találhatóak:

<?xml version="1.0"?>
<doc>
    <assembly>
        <name>ConsoleApp1</name>
    </assembly>
    <members>
        <member name="T:C">
            <summary>
            My type
            </summary>
        </member>
        <member name="P:C.Item(System.Int32)">
            <summary>
            <paramref name="x"/> // warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'x', but there is no parameter by that name
            <paramref name="y"/> // ok. 'Go To Definition' will go to 'int y'.
            </summary>
        </member>
    </members>
</doc>

Ez zavaró lehet, mert a metaadat-aláírás a definíciórész paraméterneveit fogja használni. A keveredés elkerülése érdekében javasoljuk, hogy a paraméterek nevei egyezzenek a részek között.

Indexelők

A 2022. november 2-i LDM-értekezletenaz indexelők támogatva lesznek ezzel a funkcióval.

Az indexelők nyelvtana a következőképpen módosul:

indexer_declaration
-    : attributes? indexer_modifier* indexer_declarator indexer_body
+    : attributes? indexer_modifier* 'partial'? indexer_declarator indexer_body
-    | attributes? indexer_modifier* ref_kind indexer_declarator ref_indexer_body
+    | attributes? indexer_modifier* 'partial'? ref_kind indexer_declarator ref_indexer_body
    ;

A részleges indexelő paramétereknek egyezniük kell a deklarációk között a Egyező aláírásokszabályai szerint. attribútumok egyesítése részleges indexelőparaméterek között történik.

partial class C
{
    public partial int this[int x] { get; set; }
    public partial int this[int x]
    {
        get => this._store[x];
        set => this._store[x] = value;
    }
}

// attribute merging
partial class C
{
    public partial int this[[Attr1] int x]
    {
        [Attr2] get;
        set;
    }

    public partial int this[[Attr3] int x]
    {
        get => this._store[x];
        [Attr4] set => this._store[x] = value;
    }

    // results in a merged member emitted to metadata:
    public int this[[Attr1, Attr3] int x]
    {
        [Attr2] get => this._store[x];
        [Attr4] set => this._store[x] = value;
    }
}

Nyitott kérdések

Egyéb tagtípusok

A közösség egyik tagja elindított egy megbeszélést, hogy részleges eseményektámogatását kérje. A LDM 2022. november 2-i értekezleténúgy döntöttünk, hogy elhalasztjuk az események támogatását, részben azért, mert addig senki sem kérte. Érdemes lehet újra áttekinteni ezt a kérdést, mivel ez a kérés már be is érkezett, és már több mint egy éve, hogy legutóbb megvitattuk.

A konstruktorok, operátorok, mezők és így tovább részleges deklarációinak engedélyezésével még tovább mehetnénk, de nem világos, hogy ezek tervezési terhe indokolt-e, csak azért, mert már részleges tulajdonságokat végzünk.