Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Not
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 samlas in i de relevanta LDM-anteckningar (Language Design Meeting).
Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.
Championfråga: https://github.com/dotnet/csharplang/issues/124
Sammanfattning
När generiska objekt introducerades i C# 2.0 tilläts inte attributklasser att delta. Vi kan göra språket mer komponerbart genom att snarare lossa den här begränsningen. .NET Core-körningen har lagt till stöd för generiska attribut. Allt som saknas är stöd för generiska attribut i kompilatorn.
Motivation
För närvarande kan attributförfattare ta en System.Type
som en parameter och låta användare skicka ett typeof
uttryck för att tillhandahålla attributet med de typer som behövs. Men utanför analysverktygen finns det inget sätt för en attributförfattare att begränsa vilka typer som tillåts skickas till ett attribut via typeof
. Om attribut kan vara generiska kan attributförfattare använda det befintliga systemet av typparameterbegränsningar för att uttrycka kraven för de typer som de tar som indata.
Detaljerad design
Följande avsnitt ändras: §15.2.4.2
Den direkta basklassen för en klasstyp får inte vara någon av följande typer: System.Array, System.Delegate, System.MulticastDelegate, System.Enum eller System.ValueType.
Dessutom kan en allmän klassdeklaration inte använda System.Attribute som en direkt eller indirekt basklass.
En viktig anmärkning är att följande avsnitt i specifikationen inte påverkas när du refererar till användningspunkten för ett attribut, dvs. i en attributlista: Typparametrar - §8.5.
En typparameter kan inte användas någonstans inom ett attribut.
Det innebär att när ett generiskt attribut används måste dess konstruktion vara helt "stängd", dvs. inte innehålla några typparametrar, vilket innebär att följande fortfarande är otillåtet:
using System;
using System.Collections.Generic;
public class Attr<T1> : Attribute { }
public class Program<T2>
{
[Attr<T2>] // error
[Attr<List<T2>>] // error
void M() { }
}
När ett generiskt attribut används i en attributlista har dess typargument samma begränsningar som typeof
har på argumentet. Till exempel är [Attr<dynamic>]
ett fel. Det beror på att "attributberoende" typer som dynamic
, List<string?>
, nint
och så vidare inte kan representeras fullt ut i den slutliga IL:n för ett attributtypargument, eftersom det inte finns någon symbol att "koppla" DynamicAttribute
eller annat välkänt attribut till.
Nackdelar
Att ta bort begränsningen, resonera kring konsekvenserna och lägga till lämpliga tester är arbete.
Alternativ
Attributförfattare som vill att användare ska kunna identifiera kraven för de typer som de tillhandahåller till attribut måste skriva analysverktyg och vägleda sina användare att använda analysverktygen i sina versioner.
Olösta frågor
- [x] Vad betyder
AllowMultiple = false
för ett generiskt attribut? Om vi har[Attr<string>]
och[Attr<object>]
båda används på en symbol, betyder det att "flera" av attributet används?- För tillfället är vi benägna att ta den mer restriktiva vägen här och överväga attributklassens ursprungliga definition när vi bestämmer om flera av den har tillämpats. Med andra ord är
[Attr<string>]
och[Attr<object>]
som tillämpas tillsammans inte kompatibla medAllowMultiple = false
.
- För tillfället är vi benägna att ta den mer restriktiva vägen här och överväga attributklassens ursprungliga definition när vi bestämmer om flera av den har tillämpats. Med andra ord är
Designa möten
- https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-02-21.md#generic-attributes
- På den tiden fanns det en oro för att vi skulle behöva begränsa funktionen beroende på om målmiljön stöder funktionen. (Nu stöder vi dock bara C# 10 på .NET 6. Det skulle vara trevligt för implementeringen att vara medveten om vilket minimimålramverk som stöder funktionen, men verkar mindre viktigt idag.)
C# feature specifications