Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Annotazioni
Questo articolo è una specifica delle funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.
Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Tali differenze vengono riportate nelle note pertinenti della riunione di progettazione linguistica (LDM) .
Ulteriori dettagli sul processo di adozione delle specifiche di funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche .
Questione prioritaria: https://github.com/dotnet/csharplang/issues/9058
Riassunto
Consentire al partial modificatore di eventi e costruttori di separare le parti di dichiarazione e implementazione, in modo simile a metodi parziali e proprietà/indicizzatori parziali.
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 { }
}
}
Motivazione
C# supporta già metodi, proprietà e indicizzatori parziali. Mancano eventi e costruttori parziali.
Gli eventi parziali sono utili per le librerie di eventi deboli, in cui l'utente potrebbe scrivere definizioni:
partial class C
{
[WeakEvent]
partial event Action<int, string> MyEvent;
void M()
{
RaiseMyEvent(0, "a");
}
}
E un generatore di origine fornito dalla libreria fornirà implementazioni:
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);
}
}
Gli eventi parziali e i costruttori parziali sono utili anche per generare codice di interoperabilità come in Xamarin , in cui l'utente potrebbe scrivere definizioni di costruttore e eventi parziali:
partial class AVAudioCompressedBuffer : AVAudioBuffer
{
[Export("initWithFormat:packetCapacity:")]
public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity);
[Export("create:")]
public partial event EventHandler Created;
}
E il generatore di origine genererà le associazioni (in questo caso a 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 { /* ... */ }
}
}
Progettazione dettagliata
Generale
La sintassi della dichiarazione di evento (§15.8.1) viene estesa per consentire il partial modificatore:
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 '}'
;
La sintassi della dichiarazione del costruttore di istanza (§15.11.1) è stata estesa per consentire il modificatore partial:
constructor_declaration
- : attributes? constructor_modifier* constructor_declarator constructor_body
+ : attributes? constructor_modifier* 'partial'? constructor_declarator constructor_body
;
Si noti che esiste una proposta per consentire il partial modificatore ovunque tra modificatori, anziché solo come ultimo (anche per le dichiarazioni di metodo, proprietà e tipo).
Una dichiarazione di evento con il partial modificatore è detta dichiarazione di evento parziale ed è associata a uno o più eventi parziali con i nomi specificati (si noti che una dichiarazione di evento senza funzioni di accesso può definire più eventi).
Una dichiarazione del costruttore con il partial modificatore è detta dichiarazione di costruttore parziale ed è associata a un costruttore parziale con la firma specificata.
Una dichiarazione di evento parziale viene detta dichiarazione di implementazione quando specifica il o ha il modificatore event_accessor_declarations.
In caso contrario, si tratta di una dichiarazione di definizione.
Una dichiarazione di costruttore parziale è detta dichiarazione di definizione quando ha un corpo con punto e virgola e manca il modificatore extern.
In caso contrario, si tratta di una dichiarazione di implementazione .
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 { } }
}
Solo la dichiarazione definitoria di un membro parziale partecipa all'operazione di ricerca e viene considerata nei siti di utilizzo e per l'emissione dei metadati. Ad eccezione dei commenti di documentazione, come descritto di seguito. La firma di dichiarazione di implementazione viene utilizzata per l'analisi di nullabilità dei corpi associati.
Evento o costruttore parziale:
- Può essere dichiarato solo come membro di un tipo parziale.
- Deve avere una definizione e una dichiarazione di implementazione.
- Non è consentito utilizzare il modificatore
abstract. - Impossibile implementare in modo esplicito un membro dell'interfaccia.
Un evento parziale non è simile a un campo (§15.8.2), ad esempio:
- Non dispone di alcuna risorsa di archiviazione o funzione di accesso di backup generata dal compilatore.
- Può essere usato solo in
+=e-=operazioni, non come valore.
Una dichiarazione di costruttore parziale che definisce non può avere un inizializzatore di costruttore (: this() o : base(); §15.11.2).
Interruzione di analisi
Consentire il partial modificatore in più contesti è una modifica significativa.
class C
{
partial F() => new partial(); // previously a method, now a constructor
@partial F() => new partial(); // workaround to keep it a method
}
class partial { }
Per semplificare il parser del linguaggio, il modificatore partial è accettato in qualsiasi dichiarazione simile a un metodo (ovvero, sia nelle funzioni locali che nei metodi di script di livello superiore), anche se non specifichiamo esplicitamente le modifiche alla grammatica.
Attributi
Gli attributi dell'evento o del costruttore risultanti sono gli attributi combinati delle dichiarazioni parziali nelle posizioni corrispondenti. Gli attributi combinati vengono concatenati in un ordine non specificato e i duplicati non vengono rimossi.
Il methodattribute_target (§22.3) viene ignorato nelle dichiarazioni di eventi parziali.
Gli attributi della funzione di accesso vengono usati solo dalle dichiarazioni della funzione di accesso (che possono essere presenti solo nella dichiarazione di implementazione).
Si noti che param e returnattribute_targets sono già ignorati in tutte le dichiarazioni di evento.
Gli attributi caller-info nella dichiarazione di implementazione vengono ignorati dal compilatore come specificato dalla proposta di proprietà parziale nella sezione Attributi caller-info (si noti che si applica a tutti i membri parziali che includono eventi parziali e costruttori).
Firme
Entrambe le dichiarazioni di un membro parziale devono avere firme corrispondenti simili alle proprietà parziali:
- Differenze tra tipi e tipi di riferimento tra dichiarazioni parziali significative per il runtime generano un errore in fase di compilazione.
- Le differenze nei nomi degli elementi delle tuple tra dichiarazioni parziali generano un errore in fase di compilazione.
- Le dichiarazioni devono avere gli stessi modificatori, anche se i modificatori possono essere visualizzati in un ordine diverso.
- Eccezione: questo non si applica al
externmodificatore che può essere visualizzato solo nella dichiarazione di implementazione.
- Eccezione: questo non si applica al
- Tutte le altre differenze sintattiche nelle firme delle dichiarazioni parziali generano un avviso in fase di compilazione, con le eccezioni seguenti:
- Gli elenchi di attributi non devono corrispondere come descritto in precedenza.
- Le differenze di contesto annullabile, ad esempio oblivious e annotated, non generano segnalazioni.
- Non è necessario che i valori dei parametri predefiniti corrispondano, ma viene segnalato un avviso quando la dichiarazione del costruttore di implementazione ha valori di parametro predefiniti (perché tali valori verrebbero ignorati perché solo la dichiarazione di definizione partecipa alla ricerca).
- Si verifica un avviso quando i nomi dei parametri differiscono tra la definizione e l'implementazione delle dichiarazioni del costruttore.
- Le differenze di nullità che non comportano la nullabilità inconsapevole generano avvisi.
Commenti sulla documentazione
È consentito includere commenti del documento sia sulla definizione che sulla dichiarazione di implementazione. Si noti che i commenti del documento non sono supportati nelle funzioni di accesso agli eventi.
Quando i commenti della documentazione compaiono solo in una delle dichiarazioni di un membro parziale, questi commenti vengono usati normalmente (visualizzati tramite le API Roslyn, inclusi nel file XML della documentazione).
Quando i commenti del documento sono presenti in entrambe le dichiarazioni di un membro parziale, vengono eliminati tutti i commenti del documento sulla dichiarazione di definizione e vengono usati solo i commenti del documento sulla dichiarazione di implementazione.
Quando i nomi dei parametri differiscono tra le dichiarazioni di un membro parziale, paramref gli elementi usano i nomi dei parametri della dichiarazione associata al commento della documentazione nel codice sorgente.
Ad esempio, un paramref oggetto in un commento di un documento inserito in una dichiarazione di implementazione fa riferimento ai simboli dei parametri della dichiarazione di implementazione usando i relativi nomi di parametro.
Ciò può generare confusione, perché la firma dei metadati userà i nomi dei parametri della dichiarazione di definizione.
È consigliabile assicurarsi che i nomi dei parametri corrispondano tra le dichiarazioni di un membro parziale per evitare questa confusione.
Domande aperte
Tipi di membro
Vogliamo eventi parziali, costruttori, operatori, campi? Proponiamo i primi due tipi di membri, ma qualsiasi altro subset potrebbe essere considerato.
I costruttori primari parziali possono anche essere considerati, ad esempio, consentendo all'utente di avere lo stesso elenco di parametri in più dichiarazioni di tipo parziale.
Posizioni degli attributi
È necessario riconoscere l'identificatore di destinazione dell'attributo [method:] per gli eventi parziali (o solo le dichiarazioni di definizione)?
Gli attributi degli accessor risultanti saranno quindi la concatenazione degli attributi di destinazione method da entrambe le parti della dichiarazione (o solo la definizione), più gli attributi auto-rating e targeting method dagli accessor della dichiarazione di implementazione.
La combinazione di attributi di tipi di dichiarazione diversi sarebbe senza precedenti e in effetti l'implementazione corrente di corrispondenza degli attributi in Roslyn non supporta tale operazione.
È anche possibile prendere in considerazione il riconoscimento di [param:] e [return:], non solo in occasione di eventi parziali, ma anche per tutti gli eventi simili ai campi ed esterni.
Per altri dettagli, vedere https://github.com/dotnet/roslyn/issues/77254.
C# feature specifications