Extension des méthodes partielles
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 différences 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/3301
Récapitulatif
Cette proposition vise à supprimer toutes les restrictions relatives aux signatures des méthodes partial
en C#. L'objectif est d'élargir l'ensemble des scénarios dans lesquels ces méthodes peuvent fonctionner avec les générateurs de sources et d'offrir une forme de déclaration plus générale pour les méthodes C#.
Voir aussi la spécification originale des méthodes partielles (§15.6.9).
Motivation
C# a un support limité pour les développeurs qui divisent les méthodes en déclarations et définitions / implémentations.
partial class C
{
// The declaration of C.M
partial void M(string message);
}
partial class C
{
// The definition of C.M
partial void M(string message) => Console.WriteLine(message);
}
L'un des comportements des méthodes partial
est que lorsque la définition est absente, le langage efface simplement tous les appels à la méthode partial
. Essentiellement, cela se comporte comme un appel à une méthode [Conditional]
où la condition a été évaluée à faux.
partial class D
{
partial void M(string message);
void Example()
{
M(GetIt()); // Call to M and GetIt erased at compile time
}
string GetIt() => "Hello World";
}
La motivation initiale de cette fonctionnalité était la génération de sources sous la forme de code généré par le concepteur. Les utilisateurs modifiaient constamment le code généré parce qu'ils voulaient en accrocher un aspect. Il s'agit notamment de certaines parties du processus de démarrage de Windows Forms, après l'initialisation des composants.
L'édition du code généré était sujette à erreur, car toute action obligeant le concepteur à régénérer le code entraînait l'effacement de la modification effectuée par l'utilisateur. La fonctionnalité de la méthode partial
a réduit cette tension, car elle a permis aux concepteurs d'implémenter des hooks sous la forme de méthodes partial
.
Les concepteurs pouvaient émettre des crochets comme partial void OnComponentInit()
et les développeurs pouvaient définir des déclarations pour eux ou ne pas les définir. Dans les deux cas, même si le code généré compile, les développeurs intéressés par le processus peuvent s'y intégrer selon les besoins.
Cela signifie que les méthodes partielles sont soumises à plusieurs restrictions :
- Doit avoir un type de retour
void
. - Ne peut pas avoir de paramètres
out
. - Ne peut avoir aucune accessibilité (implicitement
private
).
Ces restrictions existent parce que le langage doit être capable d'émettre du code lorsque le site d'appel est effacé. Étant donné qu'ils peuvent être effacés, private
est la seule accessibilité possible parce que le membre ne peut pas être exposé dans les métadonnées de l'assemblage. Ces restrictions servent également à limiter l'ensemble des scénarios dans lesquels les méthodes partial
peuvent être appliquées.
La présente proposition vise à supprimer toutes les restrictions existantes concernant les méthodes partial
. En fait, il faut les laisser avoir des paramètres out
, des types de retour non vides ou n'importe quel type d'accessibilité. Ces déclarations partial
auraient alors l'exigence supplémentaire qu'une définition doit exister. Cela signifie que le langage ne doit pas tenir compte de l'impact de l'effacement des sites d'appel.
Cela développerait l’ensemble des scénarios de générateur auxquels les méthodes partial
pourraient participer et s'intégrerait bien à notre fonctionnalité de générateurs de code source. Par exemple, une expression régulière peut être définie à l'aide du modèle suivant :
[RegexGenerated("(dog|cat|fish)")]
partial bool IsPetMatch(string input);
Le développeur dispose ainsi d'un moyen déclaratif simple d'opter pour les générateurs et ces derniers disposent d'un ensemble de déclarations très facile à consulter dans le code source pour piloter la sortie générée.
Comparez cela à la difficulté qu'aurait un générateur à connecter le bout de code suivant.
var regex = new RegularExpression("(dog|cat|fish)");
if (regex.IsMatch(someInput))
{
}
Étant donné que le compilateur n’autorise pas les générateurs à modifier la connexion du code à ce schéma, cela serait pratiquement impossible pour les générateurs. Ils devraient avoir recours à la réflexion dans l'implémentation de IsMatch
, ou demander aux utilisateurs de changer leurs sites d'appel vers une nouvelle méthode + refactoriser la regex pour passer le littéral de chaîne en tant qu'argument. C'est assez compliqué.
Conception détaillée
La langue changera pour permettre aux méthodes partial
d’être annotées avec un modificateur d’accessibilité explicite. Cela signifie qu'ils peuvent être étiquetés comme private
, public
, etc ...
Lorsqu'une méthode partial
comporte un modificateur d'accessibilité explicite, le langage exigera que la déclaration comporte une définition correspondante, même si l'accessibilité est private
:
partial class C
{
// Okay because no definition is required here
partial void M1();
// Okay because M2 has a definition
private partial void M2();
// Error: partial method M3 must have a definition
private partial void M3();
}
partial class C
{
private partial void M2() { }
}
En outre, le langage lèvera toutes les restrictions sur ce qui peut apparaître sur une méthode partial
qui a un modificateur d'accessibilité explicite. Ces déclarations peuvent contenir des types de retour non vides, des paramètres out
, un modificateur extern
, etc. Ces signatures bénéficieront de toute l'expressivité du langage C#.
partial class D
{
// Okay
internal partial bool TryParse(string s, out int i);
}
partial class D
{
internal partial bool TryParse(string s, out int i) { ... }
}
Cela permet explicitement aux méthodes partial
de participer aux implémentations overrides
et interface
:
interface IStudent
{
string GetName();
}
partial class C : IStudent
{
public virtual partial string GetName();
}
partial class C
{
public virtual partial string GetName() => "Jarde";
}
Le compilateur modifiera l'erreur qu'il émet lorsqu'une méthode partial
contient un élément illégal pour dire essentiellement :
Impossible d'utiliser
ref
sur une méthodepartial
qui ne dispose pas d'une accessibilité explicite.
Cela permettra d'orienter les développeurs dans la bonne direction lors de l'utilisation de cette fonctionnalité.
Restrictions :
- Les déclarations
partial
avec une accessibilité explicite doivent avoir une définition partial
Les déclarations et les signatures de définition doivent correspondre à tous les modificateurs de méthode et de paramètre. Les seuls aspects qui peuvent différer sont les noms des paramètres et les listes d'attributs (il ne s'agit pas d'une nouveauté, mais plutôt d'une exigence existante des méthodespartial
).
Questions
partielle pour tous les membres
Étant donné que nous développons partial
pour être plus convivial aux générateurs de code source, devrions-nous aussi l'étendre pour qu'il fonctionne sur tous les éléments d'une classe ? Par exemple, nous devrions pouvoir déclarer partial
constructeurs, opérateurs, etc...
Résolution L’idée est solide, mais à ce stade de la planification de C# 9, nous essayons d’éviter le glissement inutile des fonctionnalités. Vous souhaitez résoudre le problème immédiat de l'extension de la fonctionnalité pour qu'elle fonctionne avec des générateurs de sources modernes.
L'extension de partial
pour prendre en charge d'autres membres sera envisagée pour la version C# 10. Il semble probable que nous envisagerons cette extension. Cette proposition reste active, mais n'a pas encore été mise en œuvre.
Utiliser abstract au lieu de partial
L'essentiel de cette proposition consiste à s'assurer qu'une déclaration a une définition/implémentation correspondante. Faut-il utiliser abstract
étant déjà un mot-clé de langage imposant au développeur de réfléchir à une implémentation ?
Résolution Cette question a fait l'objet d'une saine discussion, mais a finalement été rejetée. Oui, les exigences sont familières, mais les concepts sont sensiblement différents. Cela pourrait facilement faire croire au développeur qu'il crée des emplacements virtuels alors que ce n'est pas le cas.
C# feature specifications