Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Remarque
Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Elle inclut les changements de spécification proposés, ainsi que les informations nécessaires à la conception et au développement de la fonctionnalité. Ces articles sont publiés jusqu'à ce que les changements proposés soient finalisés et incorporés dans la spécification ECMA actuelle.
Il peut y avoir des divergences entre la spécification de la fonctionnalité et l'implémentation réalisée. Ces différences sont capturées dans les notes de réunion de conception de langage (LDM) pertinentes .
Pour en savoir plus sur le processus d'adoption des speclets de fonctionnalité dans la norme du langage C#, consultez l'article sur les spécifications.
Problème de champion : https://github.com/dotnet/csharplang/issues/9058
Résumé
Autorisez le partial
modificateur sur les événements et les constructeurs à séparer les parties de déclaration et d’implémentation, comme les méthodes partielles et les propriétés/indexeurs partiels.
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 { }
}
}
Motivation
C# prend déjà en charge les méthodes partielles, les propriétés et les indexeurs. Les événements partiels et les constructeurs sont manquants.
Les événements partiels sont utiles pour les bibliothèques d’événements faibles , où l’utilisateur peut écrire des définitions :
partial class C
{
[WeakEvent]
partial event Action<int, string> MyEvent;
void M()
{
RaiseMyEvent(0, "a");
}
}
Et un générateur source fourni par une bibliothèque fournit des implémentations :
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);
}
}
Les événements partiels et les constructeurs partiels sont également utiles pour générer du code d’interopérabilité comme dans Xamarin , où l’utilisateur peut écrire des définitions de constructeur partiel et d’événement :
partial class AVAudioCompressedBuffer : AVAudioBuffer
{
[Export("initWithFormat:packetCapacity:")]
public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity);
[Export("create:")]
public partial event EventHandler Created;
}
Et le générateur source générerait les liaisons (à Objective-C dans ce cas) :
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 { /* ... */ }
}
}
Conception détaillée
Généralités
La syntaxe de déclaration d’événement (§15.8.1) est étendue pour autoriser le partial
modificateur :
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 syntaxe de déclaration du constructeur d’instance (§15.11.1) est étendue pour autoriser le partial
modificateur :
constructor_declaration
- : attributes? constructor_modifier* constructor_declarator constructor_body
+ : attributes? constructor_modifier* 'partial'? constructor_declarator constructor_body
;
Notez qu’il existe une proposition pour autoriser le modificateur n’importe où parmi les modificateurs, plutôt que seulement comme la dernière (également pour les partial
déclarations de méthode, de propriété et de type).
Une déclaration d’événement avec le partial
modificateur est considérée comme une déclaration d’événement partielle et elle est associée à un ou plusieurs événements partiels avec les noms spécifiés (notez qu’une déclaration d’événement sans accesseurs peut définir plusieurs événements).
Une déclaration de constructeur avec le partial
modificateur est considérée comme une déclaration de constructeur partiel et elle est associée à un constructeur partiel avec la signature spécifiée.
Une déclaration d’événement partiel est considérée comme une déclaration d’implémentation lorsqu’elle spécifie le event_accessor_declarations
modificateur ou qu’elle a le extern
modificateur.
Sinon, il s’agit d’une déclaration de définition.
Une déclaration de constructeur partielle est considérée comme une déclaration de définition lorsqu’elle a un corps de point-virgule et qu’elle n’a pas le extern
modificateur.
Sinon, c’est une déclaration d’implémentation.
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 { } }
}
Seule la déclaration de définition d’un membre partiel participe à la recherche et est prise en compte aux emplacements d’utilisation et pour l’émission des métadonnées. (À l’exception des commentaires sur la documentation comme indiqué ci-dessous.) La signature de déclaration d’implémentation est utilisée pour l’analyse nullable des corps associés.
Un événement partiel ou un constructeur :
- Peut uniquement être déclaré en tant que membre d’un type partiel.
- Doit avoir une déclaration de définition et une déclaration d’implémentation.
- Il n'est pas permis d'avoir le
abstract
modificateur. - Impossible d’implémenter explicitement un membre d’interface.
Un événement partiel n’est pas de type champ (§15.8.2), c’est-à-dire :
- Il n'a pas de stockage de secours ni d'accesseurs générés par le compilateur.
- Elle ne peut être utilisée que dans
+=
et-=
les opérations, et non pas en tant que valeur.
Une déclaration de constructeur partiel définissant ne peut pas avoir d’initialiseur de constructeur (: this()
ou : base()
; §15.11.2).
Interruption de l’analyse
L’autorisation du modificateur partial
dans d’autres contextes est un changement cassant :
class C
{
partial F() => new partial(); // previously a method, now a constructor
@partial F() => new partial(); // workaround to keep it a method
}
class partial { }
Pour simplifier l’analyseur de langage, le partial
modificateur est accepté à n’importe quelle déclaration de type méthode (c’est-à-dire, les fonctions locales et les méthodes de script de niveau supérieur), même si nous ne spécifions pas les modifications grammaticales explicitement ci-dessus.
Attributs
Les attributs de l’événement ou du constructeur résultant sont les attributs combinés des déclarations partielles dans les positions correspondantes. Les attributs combinés sont concaténés dans un ordre non spécifié et les doublons ne sont pas supprimés.
Le method
attribute_target (§22.3) est ignoré sur les déclarations d’événements partiels.
Les attributs d’accesseur sont utilisés uniquement dans les déclarations d’accesseur (qui peuvent être présentes uniquement sous la déclaration d’implémentation).
Notez que param
et return
les attribute_targetsont déjà ignorés sur toutes les déclarations d’événement.
Les attributs d'informations de l'appelant sur la déclaration d'implémentation sont ignorés par le compilateur, comme spécifié par la proposition de propriétés partielles dans la section des attributs Caller-info (notez qu'elle s'applique à tous les membres partiels, qui incluent des événements partiels et des constructeurs).
Signatures
Les deux déclarations d’un membre partiel doivent avoir des signatures correspondantes similaires aux propriétés partielles :
- Les différences de type et de type ref entre les déclarations partielles qui sont significatives pour le runtime entraînent une erreur au moment de la compilation.
- Les différences entre les noms des éléments de tuple dans les déclarations partielles entraînent une erreur au moment de la compilation.
- Les déclarations doivent avoir les mêmes modificateurs, bien que les modificateurs puissent apparaître dans un ordre différent.
- Exception : cela ne s’applique pas au
extern
modificateur qui peut apparaître uniquement sur la déclaration d’implémentation.
- Exception : cela ne s’applique pas au
- Toutes les autres différences syntaxiques dans les signatures de déclarations partielles entraînent un avertissement au moment de la compilation, avec les exceptions suivantes :
- Les listes d’attributs n’ont pas besoin de correspondre comme décrit ci-dessus.
- Les différences de contextes nullables (telles que inconscient vs. annoté) ne provoquent pas d’avertissements.
- Les valeurs de paramètre par défaut n’ont pas besoin de correspondre, mais un avertissement est signalé lorsque la déclaration du constructeur d’implémentation a des valeurs de paramètre par défaut (car celles-ci ne sont ignorées que dans la mesure où seule la déclaration de définition participe à la recherche).
- Un avertissement se produit lorsque les noms de paramètres diffèrent entre la définition et l’implémentation de déclarations de constructeur.
- Les différences de nullabilité qui n’impliquent pas une nullabilité oblivieuse génèrent des avertissements.
Commentaires de documentation
Il est permis d'inclure des commentaires de document dans les déclarations de définition et d’implémentation. Notez que les commentaires sur la documentation ne sont pas pris en charge sur les accesseurs d’événements.
Lorsque des commentaires de documentation sont présents uniquement sur une déclaration d’un membre partiel, ces commentaires sont utilisés normalement (exposés par le biais des API Roslyn, émis dans le fichier XML de documentation).
Lorsque des commentaires de document sont présents sur les deux déclarations d’un membre partiel, tous les commentaires de la documentation sur la déclaration de définition sont supprimés et seuls les commentaires de document sur la déclaration d’implémentation sont utilisés.
Lorsque les noms de paramètres diffèrent entre les déclarations d’un membre partiel, paramref
les éléments utilisent les noms de paramètres de la déclaration associée au commentaire de documentation dans le code source.
Par exemple, un paramref
commentaire de document placé sur une déclaration d’implémentation fait référence aux symboles de paramètre de la déclaration d’implémentation à l’aide de leurs noms de paramètres.
Cela peut prêter à confusion, car la signature de métadonnées utilise des noms de paramètres à partir de la déclaration de définition.
Il est recommandé de s’assurer que les noms de paramètres correspondent aux déclarations d’un membre partiel pour éviter cette confusion.
Questions ouvertes
Types de membres
Voulons-nous des événements partiels, des constructeurs, des opérateurs, des champs ? Nous proposons les deux premiers types de membres, mais tout autre sous-ensemble peut être pris en compte.
Les constructeurs principaux partiels peuvent également être considérés, par exemple, pour permettre à l’utilisateur d’avoir la même liste de paramètres sur plusieurs déclarations de type partiel.
Emplacements des attributs
Devons-nous reconnaître le [method:]
spécificateur cible d’attribut pour les événements partiels (ou simplement les déclarations de définition) ?
Ensuite, les attributs d’accesseur qui en résultent seraient la concaténation des attributs de ciblage method
provenant des deux parties de la déclaration (ou simplement de la partie définissant) plus les attributs d’auto-ciblage et de ciblage method
provenant des accesseurs de la déclaration d’implémentation.
La combinaison d’attributs provenant de différents types de déclaration serait sans précédent et en effet, l’implémentation actuelle de la correspondance d’attributs dans Roslyn ne prend pas en charge cela.
Nous pouvons également envisager de reconnaître [param:]
et [return:]
, non seulement sur les événements partiels, mais sur tous les événements de type champ et les événements externes.
Pour plus d’informations, consultez https://github.com/dotnet/roslyn/issues/77254.
C# feature specifications