Extension GetEnumerator
pour les boucles foreach
.
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 consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).
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/3194
Récapitulatif
Permettre aux boucles foreach
de reconnaître une méthode d'extension GetEnumerator
qui satisfait par ailleurs au motif foreach, et de boucler sur l'expression lorsque cela constituerait autrement une erreur.
Motivation
Cela alignera foreach
sur la manière dont d'autres fonctionnalités de C# sont implémentées, telles que la déconstruction asynchrone et basée sur des modèles.
Conception détaillée
La modification de la spécification est relativement simple. Nous modifions la section du §13.9.5 de
Le traitement à la compilation d'une instruction foreach détermine d'abord le type de collection, le type d'énumérateur et le type d'élément de l'expression. Cette détermination se déroule comme suit :
Si le type
X
de l'expression est un type de tableau, il y a une conversion de référence implicite deX
vers l'interfaceIEnumerable
(puisqueSystem.Array
implémente cette interface). Le type de collection est l'interfaceIEnumerable
, le type d'énumérateur est l'interfaceIEnumerator
et le type d'élément est le type d'élément du type de tableauX
.Si le type
X
de l'expression estdynamic
, il y a une conversion implicite de l'expression vers l'interfaceIEnumerable
(§10.2.10). Le type de collection est l'interfaceIEnumerable
et le type d'énumérateur est l'interfaceIEnumerator
. Si l'identificateurvar
est donné comme type de variable locale, le type de l'élément etdynamic
, sinon il estobject
.Sinon, déterminez si le type
X
possède une méthodeGetEnumerator
appropriée :
- Effectuer une recherche de membre sur le type
X
avec l'identifiantGetEnumerator
et aucun argument de type. Si la recherche de membres ne produit pas de correspondance, si elle produit une ambiguïté ou si elle produit une correspondance qui n'est pas un groupe de méthodes, vérifiez s'il s'agit d'une interface énumérable comme décrit ci-dessous Il est recommandé d'émettre un problème si la recherche de membres produit autre chose qu'un groupe de méthodes ou aucune correspondance.- Effectuez la résolution de surcharge en utilisant le groupe de méthodes résultant et une liste d'arguments vide Si la résolution de surcharge n'entraîne aucune méthode applicable, aboutit à une ambiguïté ou aboutit à une seule meilleure méthode mais que cette méthode est soit statique, soit non publique, vérifiez la présence d'une interface énumérable comme décrit ci-dessous. Il est recommandé d'émettre un problème si la résolution des surcharges produit autre chose qu'une méthode d'instance publique non ambiguë ou aucune méthode applicable.
- Si le type de retour
E
de la méthodeGetEnumerator
n'est pas un type de classe, de structure ou d'interface, une erreur est produite et aucune autre mesure n'est prise.- La recherche de membre est effectuée sur
E
avec l'identifiantCurrent
et aucun argument de type. Si la recherche de membre ne produit aucune correspondance, si le résultat est une erreur ou si le résultat est autre chose qu'une propriété d'instance publique permettant la lecture, une erreur est produite et aucune autre mesure n'est prise.- La recherche de membre est effectuée sur
E
avec l'identifiantMoveNext
et aucun argument de type. Si la recherche de membres ne produit aucune correspondance, si le résultat est une erreur ou si le résultat est autre chose qu'un groupe de méthodes, une erreur est produite et aucune autre mesure n'est prise.- La résolution de surcharge est effectuée sur le groupe de méthodes avec une liste d'arguments vide. Si la résolution de surcharge n'aboutit à aucune méthode applicable, si elle aboutit à une ambiguïté ou si elle aboutit à une seule méthode optimale, mais que cette méthode est statique ou non publique, ou que son type de retour n'est pas
bool
, une erreur est générée et aucune autre mesure n'est prise.- Le type de collection est
X
, le type d'énumérateur estE
et le type d'élément est le type de la propriétéCurrent
.Sinon, vérifiez la présence d'une interface énumérable :
- Si, parmi tous les types
Ti
pour lesquels il existe une conversion implicite deX
enIEnumerable<Ti>
, il existe un typeT
unique tel queT
n'est pasdynamic
et que, pour tous les autresTi
, il existe une conversion implicite deIEnumerable<T>
enIEnumerable<Ti>
, alors le type de collection est l'interfaceIEnumerable<T>
, le type d'énumérateur est l'interfaceIEnumerator<T>
et le type d'élément estT
.- Dans le cas contraire, s'il existe plus d'un type
T
, une erreur est produite et aucune autre mesure n'est prise.- Sinon, s'il existe une conversion implicite de
X
vers l'interfaceSystem.Collections.IEnumerable
, le type de collection est cette interface, le type d'énumérateur est l'interfaceSystem.Collections.IEnumerator
et le type d'élément estobject
.Sinon, déterminez si le type « X » possède une méthode d'extension
GetEnumerator
appropriée :
- Effectuer une recherche de méthode d'extension sur le type
X
avec l'identifiantGetEnumerator
. Si la recherche de membres ne produit pas de correspondance, si elle produit une ambiguïté ou si elle produit une correspondance qui n'est pas un groupe de méthodes, une erreur est produite et aucune autre mesure n'est prise. Il est recommandé d'émettre un problème si la recherche de membres produit autre chose qu'un groupe de méthodes ou aucune correspondance.- Effectuez la résolution de surcharge en utilisant le groupe de méthodes résultant et un seul argument de type
X
. Si la résolution de surcharge ne produit aucune méthode applicable, si elle aboutit à une ambiguïté ou si elle produit une seule méthode optimale mais que cette méthode n'est pas accessible, une erreur est générée et aucune autre mesure n'est prise.
- Cette résolution permet au premier argument d'être transmis par ref si
X
est un type struct et que le type de ref estin
.- Si le type de retour
E
de la méthodeGetEnumerator
n'est pas un type de classe, de structure ou d'interface, une erreur est produite et aucune autre mesure n'est prise.- La recherche de membre est effectuée sur
E
avec l'identifiantCurrent
et aucun argument de type. Si la recherche de membre ne produit aucune correspondance, si le résultat est une erreur ou si le résultat est autre chose qu'une propriété d'instance publique permettant la lecture, une erreur est produite et aucune autre mesure n'est prise.- La recherche de membre est effectuée sur
E
avec l'identifiantMoveNext
et aucun argument de type. Si la recherche de membres ne produit aucune correspondance, si le résultat est une erreur ou si le résultat est autre chose qu'un groupe de méthodes, une erreur est produite et aucune autre mesure n'est prise.- La résolution de surcharge est effectuée sur le groupe de méthodes avec une liste d'arguments vide. Si la résolution de surcharge n'aboutit à aucune méthode applicable, si elle aboutit à une ambiguïté ou si elle aboutit à une seule méthode optimale, mais que cette méthode est statique ou non publique, ou que son type de retour n'est pas
bool
, une erreur est générée et aucune autre mesure n'est prise.- Le type de collection est
X
, le type d'énumérateur estE
et le type d'élément est le type de la propriétéCurrent
.Dans le cas contraire, une erreur est produite et aucune autre mesure n'est prise.
Pour await foreach
, les règles sont modifiées de la même manière. Le seul changement nécessaire à cette spécification est la suppression de la ligne Extension methods do not contribute.
de la description, car le reste de cette spécification est basé sur les règles ci-dessus avec des noms différents pour les méthodes du modèle.
Inconvénients
Chaque changement ajoute une complexité supplémentaire au langage, ce qui permet potentiellement à des choses qui n'ont pas étéforeach
conçues pour être éditées de l'êtreforeach
, comme Range
.
Alternatives
Ne rien faire.
Questions non résolues
Aucune à ce stade.
C# feature specifications