Dela via


Partiella egenskaper

Notera

Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.

Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader dokumenteras i relevanta anteckningar från Language Design Meeting (LDM) .

Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.

Champion-problem: https://github.com/dotnet/csharplang/issues/6420

Grammatik

Den grammatik för property_declaration(§14.7.1) uppdateras på följande sätt:

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

Anmärkningar: Detta är något liknande till hur method_header(§15.6.1) och class_declaration(§15.2.1) specificeras. (Observera att Issue #946 föreslår att man ska lätta på ordningskravet och skulle förmodligen tillämpas på alla deklarationer som tillåter partial modifierare. Vi avser att specificera en sådan lättnad av ordningskravet inom en snar framtid och implementera den i samma version som denna funktion implementeras.)

Definiera och implementera deklarationer

När en egenskapsdeklaration innehåller en partiell modifierare, sägs den egenskapen vara en partiell egenskap. Partiella egenskaper kan endast deklareras som medlemmar av partiella typer.

En partiell egendomsdeklaration sägs vara en definierande deklaration när dess accessorer alla har semikolonkroppar, och den saknar extern modifierare. Annars är det en implementerade deklaration.

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

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

Eftersom vi har reserverat det syntaktiska formuläret med semikolonåtkomstorgan för definiera deklarationenkan inte en partiell egenskap implementeras automatiskt. Därför justerar vi Automatiskt implementerade egenskaper (§15.7.4) enligt följande:

En automatiskt implementerad egenskap (eller automatisk egenskap för kort) är en icke-abstrakt, icke-extern, icke-partiell, icke-referensvärdesegenskap med semikolonbaserade accessor-organ.

Kommentarer. Det är användbart för kompilatorn att kunna titta på en enskild deklaration isolerat och veta om det är en definierande eller en implementeringsdeklaration. Därför vill vi inte tillåta automatiska egenskaper genom att till exempel inkludera två identiska partial egenskapsdeklarationer. Vi tror inte att användningsfallen för den här funktionen omfattar implementering av den partiella egenskapen med en autoegenskap, men i fall där en trivial implementering önskas tror vi att nyckelordet field gör det enkelt nog.


En partiell egenskap måste ha en deklaration som definierar och en deklaration som implementerar.

Kommentarer. Vi tycker inte heller att det är användbart att tillåta delning av deklarationen mellan fler än två delar, så att olika åtkomster kan implementeras på olika platser, till exempel. Därför imiterar vi helt enkelt det system som fastställts med partiella metoder.


Endast den definierande deklarationen av en partiell egenskap ingår i uppslagningen, ungefär som hur endast den definierande deklarationen av en partiell metod ingår i överlagringslösningen.

Kommentarer. I kompilatorn förväntar vi oss att endast symbolen för den definierande deklarationen visas i medlemslistan och att symbolen för implementeringsdelen kan nås via den definierande symbolen. Vissa funktioner som nullbar analys kan dock se igenom till implementeringsdeklarationen för att ge ett mer användbart beteende.

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.
    {
    }
}

En partiell egenskap tillåts inte ha abstract modifierare.

En partiell egenskap kan inte uttryckligen implementera gränssnittsegenskaper.

Attributsammanslagningen

I likhet med partiella metoder är attributen i den resulterande egenskapen de kombinerade attributen för delarna sammanfogade i en ospecificerad ordning och dubbletter tas inte bort.

Samtalsinformation-attribut

Vi justerar följande språk från standard:

Det är ett fel att ha samma anroparinfoattribut på en parameter av både den definierande och implementerande delen av en partiell -metodmedlem-deklaration. Endast anropar-info-attribut i den definierande delen tillämpas, medan attribut för anropare-info som endast förekommer i implementeringsdelen ignoreras.

  • Det beskrivna felet beror på att definitionerna för dessa attribut inte har AllowMultiple = true. Om du använder dem flera gånger, bland annat i partiella deklarationer, resulterar det i ett fel.
  • När anropar-info-attribut tillämpas på en parameter i implementeringsdelen av en partiell metod rapporterar Roslyn-kompilatorn en varning. Den rapporterar också en varning för samma scenario i en partiell egenskap.

Överensstämmande signaturer

LDM-mötet den 14 september 2020 definierade en uppsättning "strikta" krav för signaturmatchning av partiella metoder, vilka infördes i en varningsvåg. Partiella egenskaper har analoga krav till partiella metoder för signaturmatchning så långt det är möjligt, förutom att alla diagnoser av olikheter rapporteras som standard och inte skyddas av en varningsvåg.

Krav för signaturmatchning är:

  1. Typ- och referenstypvariationer mellan partiella egenskapsdeklarationer som påverkar körresultatet leder till ett kompileringsfel.
  2. Skillnader i tuppelns elementnamn i partiella egenskapsdeklarationer resulterar i ett kompileringsfel, samma som för partiella metoder.
  3. Egenskapsdeklarationerna och deras åtkomstdeklarationer måste ha samma modifierare, även om modifierarna kan visas i en annan ordning.
    • Undantag: Detta gäller inte för extern-modifieraren, som endast får visas på en som implementerar deklarationen.
  4. Alla andra syntaktiska skillnader i signaturer för partiella egenskapsdeklarationer resulterar i en kompileringstidsvarning med följande undantag:
    • Attributlistor på eller inom partiella egenskapsdeklarationer behöver inte matchas. I stället utförs sammanslagning av attribut i motsvarande positioner, enligt attributssammanslagning.
    • Nullbara kontextskillnader orsakar inte varningar. En skillnad där en av typerna är nullable-oblivious och den andra typen antingen är nullable-annotated eller not-nullable-annotated resulterar med andra ord inte i några varningar.
    • Standardparametervärdena behöver inte matcha. En varning rapporteras när implementeringsdelen av en partiell indexerare har standardparametervärden. Detta liknar en befintlig varning som inträffar när implementeringsdelen av en partiell metod har standardparametervärden.
  5. En varning inträffar när parameternamn skiljer sig åt mellan att definiera och implementera deklarationer. Parameternamnen från definitionsdelen används på användningsplatser och i generera.
  6. Nullabilitetsskillnader som inte innebär omedveten nullabilitet resulterar i varningar. När du analyserar en accessor-kropp används implementeringsdelens signatur. Definitionsdelens signatur används när du analyserar användningsplatser och i generering. Detta är förenligt med partiella metoder.
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
}

Dokumentationskommentar

Vi vill att beteendet för dokumentkommentarer på de partiella egenskaperna ska överensstämma med vad vi levererade för de partiella metoderna. Det beteendet beskrivs i https://github.com/dotnet/csharplang/issues/5193.

Det är tillåtet att inkludera dokumentkommentare för antingen definitionen eller implementeringsdelen av en partiell egenskap. (Observera att dokumentkommentarer inte stöds för egenskapsåtkomster.)

När dokumentkommentar endast finns på en av delarna i egenskapen används dessa dokumentkommentar normalt (visas via ISymbol.GetDocumentationCommentXml(), skrivs ut till XML-dokumentationsfilen osv.).

När dokumentkommentar finns på båda delarna tas alla dokumentkommentar på definitionsdelen bort och endast dokumentkommentarna på implementeringsdelen används.

Till exempel följande 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 { } }
}

Resulterar i följande XML-dokumentationsfil:

<?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>

När parameternamn skiljer sig åt mellan partiella deklarationer använder <paramref> element parameternamnen från deklarationen som är associerad med dokumentationskommentatorn i källkoden. Till exempel refererar en paramref på en dokumentkommentare som placerats på en implementeringsdeklaration till parametersymbolerna i implementeringsdeklarationen med hjälp av deras parameternamn. Detta är förenligt med partiella metoder.

/// <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.
}

Resulterar i följande XML-dokumentationsfil:

<?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>

Detta kan vara förvirrande eftersom metadatasignaturen använder parameternamn från definitionsdelen. Vi rekommenderar att du ser till att parameternamnen matchar mellan delar för att undvika den här förvirringen.

Indexerare

Per LDM-möte den 2 november 2022stöds indexerare med den här funktionen.

Indexerarnas grammatik ändras på följande sätt:

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
    ;

Parametrar för partiell indexerare måste matcha mellan deklarationer enligt samma regler som för Matchande signaturer. Attributsammanslagningen utförs över partiella indexerareparametrar.

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;
    }
}

Öppna problem

Andra medlemstyper

En gemenskapsmedlem öppnade en diskussion för att begära stöd för partiella händelser . I LDM-mötet den 2 november 2022bestämde vi oss för att skjuta upp stödet för evenemang, delvis för att ingen vid den tidpunkten begärde det. Vi kanske vill återkomma till denna fråga, eftersom denna begäran nu har kommit in, och det har gått över ett år sedan vi senast diskuterade den.

Vi skulle också kunna gå ännu längre när det gäller att tillåta partiella deklarationer av konstruktorer, operatörer, fält och så vidare, men det är oklart om designbördan för dessa är motiverad, bara för att vi redan gör partiella egenskaper.