Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Opmerking
Dit artikel is een functiespecificatie. De specificatie fungeert als het ontwerpdocument voor de functie. Het bevat voorgestelde specificatiewijzigingen, samen met informatie die nodig is tijdens het ontwerp en de ontwikkeling van de functie. Deze artikelen worden gepubliceerd totdat de voorgestelde specificaties zijn voltooid en opgenomen in de huidige ECMA-specificatie.
Er kunnen enkele verschillen zijn tussen de functiespecificatie en de voltooide implementatie. Deze verschillen worden vastgelegd in de relevante LDM-notities (Language Design Meeting).
Meer informatie over het proces voor het aannemen van functiespeclets in de C#-taalstandaard vindt u in het artikel over de specificaties.
Kampioensprobleem: https://github.com/dotnet/csharplang/issues/9058
Samenvatting
Sta de partial modifier toe op gebeurtenissen en constructoren om het declaratie- en implementatiedeel te scheiden, vergelijkbaar met gedeeltelijke methoden en gedeeltelijke eigenschappen/indexeerfuncties.
partial class C
{
partial C(int x, string y);
partial event Action<int, string> MyEvent;
}
partial class C
{
partial C(int x, string y) { }
partial event Action<int, string> MyEvent
{
add { }
remove { }
}
}
Motivatie
C# ondersteunt al gedeeltelijke methoden, eigenschappen en indexeerfuncties. Gedeeltelijke gebeurtenissen en constructors ontbreken.
Gedeeltelijke gebeurtenissen zijn handig voor zwakke gebeurtenisbibliotheken, waarbij de gebruiker definities kon schrijven:
partial class C
{
[WeakEvent]
partial event Action<int, string> MyEvent;
void M()
{
RaiseMyEvent(0, "a");
}
}
En een brongenerator die door een bibliotheek wordt geleverd, biedt implementaties:
partial class C
{
private readonly WeakEvent _myEvent;
partial event Action<int, string> MyEvent
{
add { _myEvent.Add(value); }
remove { _myEvent.Remove(value); }
}
protected void RaiseMyEvent(int x, string y)
{
_myEvent.Invoke(x, y);
}
}
Gedeeltelijke gebeurtenissen en gedeeltelijke constructors zijn ook handig voor het genereren van interoperabiliteitscode, zoals in Xamarin , waar de gebruiker gedeeltelijke constructor- en gebeurtenisdefinities kan schrijven:
partial class AVAudioCompressedBuffer : AVAudioBuffer
{
[Export("initWithFormat:packetCapacity:")]
public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity);
[Export("create:")]
public partial event EventHandler Created;
}
En de brongenerator genereert de bindingen (in dit geval aan Objective-C):
partial class AVAudioCompressedBuffer : AVAudioBuffer
{
[BindingImpl(BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]
public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity) : base(NSObjectFlag.Empty)
{
// Call Objective-C runtime:
InitializeHandle(
global::ObjCRuntime.NativeHandle_objc_msgSendSuper_NativeHandle_UInt32(
this.SuperHandle,
Selector.GetHandle("initWithFormat:packetCapacity:"),
format.GetNonNullHandle(nameof(format)),
packetCapacity),
"initWithFormat:packetCapacity:");
}
public partial event EventHandler Created
{
add { /* ... */ }
remove { /* ... */ }
}
}
Gedetailleerd ontwerp
Algemeen
Syntaxis van gebeurtenisdeclaratie (§15.8.1) wordt uitgebreid om de partial wijzigingsfunctie toe te staan:
event_declaration
- : attributes? event_modifier* 'event' type variable_declarators ';'
+ : attributes? event_modifier* 'partial'? 'event' type variable_declarators ';'
- | attributes? event_modifier* 'event' type member_name
+ | attributes? event_modifier* 'partial'? 'event' type member_name
'{' event_accessor_declarations '}'
;
De declaratiesyntaxis van instantieconstructors (§15.11.1) wordt uitgebreid om de partial modifier toe te staan:
constructor_declaration
- : attributes? constructor_modifier* constructor_declarator constructor_body
+ : attributes? constructor_modifier* 'partial'? constructor_declarator constructor_body
;
Houd er rekening mee dat er een voorstel is om de partial modifier overal tussen modifiers toe te staan, in plaats van alleen als laatste (ook voor methode-, eigenschaps- en typedeclaraties).
Een gebeurtenisdeclaratie met de partial wijzigingsfunctie wordt een gedeeltelijke gebeurtenisdeclaratie genoemd en deze is gekoppeld aan een of meer gedeeltelijke gebeurtenissen met de opgegeven namen (houd er rekening mee dat één gebeurtenisdeclaratie zonder toegangsrechten meerdere gebeurtenissen kan definiëren).
Een constructordeclaratie met de partial modifier wordt geacht een gedeeltelijke constructordeclaratie te zijn en deze is gekoppeld aan een gedeeltelijke constructor met de opgegeven handtekening.
Een gedeeltelijke gebeurtenisdeclaratie wordt een implementerende declaratie genoemd wanneer deze de event_accessor_declarations specificeert of de extern modifier heeft.
Anders is het een definiërende declaratie.
Een gedeeltelijke constructordeclaratie wordt gezegd een definiërende declaratie te zijn wanneer deze een puntkommatekst heeft en de wijzigingsfunctie ontbreekt extern .
Anders is het een implementerende declaratie.
partial class C
{
// defining declarations
partial C();
partial C(int x);
partial event Action E, F;
// implementing declarations
partial C() { }
partial C(int x) { }
partial event Action E { add { } remove { } }
partial event Action F { add { } remove { } }
}
Alleen de bepalende declaratie van een gedeeltelijk lidmaatschap neemt deel aan de zoekactie en wordt overwogen bij gebruiksplaatsen en bij het uitsturen van metadata. (Met uitzondering van documentatieopmerkingen zoals hieronder wordt beschreven.) De implementerende declaratiesignatuur wordt gebruikt voor analyse van nullable types van de bijbehorende codeblokken.
Een gedeeltelijke gebeurtenis of een constructor.
- Mag alleen worden gedeclareerd als lid van een gedeeltelijk type.
- Er moet één definitie en één uitvoeringsdeclaratie zijn.
- Het is niet toegestaan om de
abstractwijzigingsfunctie te hebben. - Kan geen interfacelid expliciet implementeren.
Een gedeeltelijke gebeurtenis is niet veldachtig (§15.8.2), bijvoorbeeld:
- Er zijn geen achterliggende opslag en accessors die door de compiler worden gegenereerd.
- Het kan alleen worden gebruikt in
+=en-=bewerkingen, niet als een waarde.
Een gedeeltelijke constructordeclaratie die definiërend is, kan geen constructorinitializer hebben (: this() of : base(); §15.11.2).
Parseringsonderbreking
Het toestaan van de partial wijziging in meer contexten is een belangrijke wijziging:
class C
{
partial F() => new partial(); // previously a method, now a constructor
@partial F() => new partial(); // workaround to keep it a method
}
class partial { }
Om de taalparser te vereenvoudigen, wordt de partial wijzigingsfunctie geaccepteerd bij elke methodeachtige declaratie (dat wil zeggen, lokale functies en scriptmethoden op het hoogste niveau), ook al geven we de grammaticawijzigingen niet expliciet hierboven op.
Kenmerken
De kenmerken van de resulterende gebeurtenis of constructor zijn de gecombineerde kenmerken van de gedeeltelijke declaraties in de bijbehorende posities. De gecombineerde kenmerken worden samengevoegd in een niet-opgegeven volgorde en duplicaten worden niet verwijderd.
De methodattribute_target (§22.3) wordt genegeerd bij gedeeltelijke gebeurtenisdeclaraties.
Accessorkenmerken worden alleen gebruikt vanuit declaraties van accessors (die alleen aanwezig kunnen zijn onder de uitvoeringsdeclaratie).
Houd er rekening mee dat param en returnattribute_targets al worden genegeerd voor alle gebeurtenisdeclaraties.
Caller-infokenmerken in de implementatiedeclaratie worden genegeerd door de compiler zoals opgegeven door het voorstel voor gedeeltelijke eigenschappen in de sectie Caller-infokenmerken (u ziet dat deze van toepassing is op alle gedeeltelijke leden die gedeeltelijke gebeurtenissen en constructors bevatten).
Handtekeningen
Beide declaraties van een gedeeltelijk lid moeten overeenkomende handtekeningen hebben die vergelijkbaar zijn met gedeeltelijke eigenschappen:
- Type- en referentietypeverschillen tussen gedeeltelijke declaraties die significant zijn voor de runtime, resulteren in een compileertijd-fout.
- Verschillen in tuple-elementnamen tussen gedeeltelijke declaraties resulteren in een compileertijdfout.
- De declaraties moeten dezelfde modifiers hebben, hoewel de modifiers in een andere volgorde kunnen worden weergegeven.
- Uitzondering: dit is niet van toepassing op de
externwijzigingsfunctie die alleen in de uitvoeringsdeclaratie mag worden weergegeven.
- Uitzondering: dit is niet van toepassing op de
- Alle andere syntactische verschillen in de handtekeningen van gedeeltelijke declaraties resulteren in een waarschuwing over de compilatietijd, met de volgende uitzonderingen:
- Kenmerklijsten hoeven niet overeen te komen zoals hierboven beschreven.
- Verschillen in nullable context (zoals nalatigheid versus geannoteerd) veroorzaken geen waarschuwingen.
- Standaardparameterwaarden hoeven niet overeen te komen, maar er wordt een waarschuwing gerapporteerd wanneer de declaratie van de implementatieconstructor standaardparameterwaarden bevat (omdat deze worden genegeerd omdat alleen de definiërende declaratie deelneemt aan de zoekactie).
- Er treedt een waarschuwing op wanneer parameternamen verschillen tussen het definiëren en implementeren van constructordeclaraties.
- Verschillen in nullabiliteit die geen niet-zichtbare nullabiliteit inhouden, resulteren in waarschuwingen.
Opmerkingen bij documentatie
Het is toegestaan om documentatie-opmerkingen op te nemen bij zowel de definiërende als de implementerende declaratie. Houd er rekening mee dat documentopmerkingen niet worden ondersteund voor gebeurtenistoegangsors.
Wanneer documentopmerkingen aanwezig zijn op slechts één van de declaraties van een gedeeltelijk lid, worden deze documentopmerkingen normaal gebruikt (weergegeven via Roslyn-API's, verzonden naar het XML-bestand van de documentatie).
Wanneer documentopmerkingen aanwezig zijn op beide declaraties van een gedeeltelijk lid, worden alle documentopmerkingen over de definiërende declaratie verwijderd en worden alleen de opmerkingen van het document over de uitvoeringsdeclaratie gebruikt.
Wanneer parameternamen verschillen tussen declaraties van een gedeeltelijk lid, paramref gebruiken elementen de parameternamen uit de declaratie die is gekoppeld aan de opmerking bij de documentatie in broncode.
Een opmerking in een document die is geplaatst op een implementatiedeclaratie verwijst bijvoorbeeld paramref naar de parametersymbolen van de implementatiedeclaratie met behulp van de parameternamen.
Dit kan verwarrend zijn, omdat de metagegevenshandtekening parameternamen uit de definiërende declaratie gebruikt.
Het wordt aanbevolen om ervoor te zorgen dat parameternamen overeenkomen met de declaraties van een gedeeltelijk lid om deze verwarring te voorkomen.
Open vragen
Ledentypen
Willen we gedeeltelijk gebruikmaken van gebeurtenissen, constructors, operators, velden? We stellen de eerste twee soorten leden voor, maar elke andere subset kan worden overwogen.
Gedeeltelijke primaire constructors kunnen ook worden overwogen, bijvoorbeeld om de gebruiker in staat te stellen dezelfde parameterlijst te hebben voor meerdere declaraties van gedeeltelijke typen.
Kenmerklocaties
Moeten we de [method:] kenmerkdoelaanduiding herkennen voor gedeeltelijke gebeurtenissen (of alleen de definiërende declaraties)?
Vervolgens zouden de resulterende kenmerken van de accessoren de combinatie zijn van method-gerichte kenmerken uit zowel (of alleen de definiërende) declaratieonderdelen plus zelfgerichte en method-gerichte kenmerken van de accessoren van de implementatiedeclaratie.
Het combineren van kenmerken uit verschillende soorten declaraties zou ongekend zijn en de huidige implementatie van kenmerkkoppeling in Roslyn biedt daar geen ondersteuning voor.
We kunnen ook overwegen om [param:] en [return:] te herkennen, niet alleen op gedeeltelijke gebeurtenissen, maar op alle veldachtige en externe gebeurtenissen.
Zie https://github.com/dotnet/roslyn/issues/77254 voor meer informatie.
C# feature specifications