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é. Il inclut les modifications de spécification proposées, ainsi que les informations nécessaires pendant la conception et le développement de la fonctionnalité. Ces articles sont publiés jusqu’à ce que les modifications de spécification proposées soient finalisées et incorporées dans la spécification ECMA actuelle.
Il peut y avoir des différences entre la spécification de la fonctionnalité et l’implémentation terminée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).
Vous pouvez en savoir plus sur le processus d’adoption des speclets de fonctionnalités dans la norme de langage C# dans l’article sur les spécifications .
Résumé
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 des spécifications est relativement simple. Nous modifions la section du §13.9.5 de
Le traitement au moment de la compilation d’une instruction foreach détermine d’abord le type de collection , type d’énumérateur et type d’élément de l’expression. Cette détermination se poursuit comme suit :
Si le type
X
de expression est un type de tableau, il existe une conversion de référence implicite deX
vers l’interface deIEnumerable
(étant donné queSystem.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 expression estdynamic
il existe une conversion implicite de expression vers l’interface deIEnumerable
(§10.2.10). Le type de collection est l’interfaceIEnumerable
et le type d’énumérateur est l’interfaceIEnumerator
. Si l’identificateurvar
est donné en tant que local_variable_type, le type d’élément estdynamic
, sinon il estobject
.Sinon, déterminez si le type
X
a 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 membre ne produit pas de correspondance, ou génère une ambiguïté ou produit une correspondance qui n’est pas un groupe de méthodes, recherchez 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 une résolution de surcharge à l’aide du groupe de méthodes résultant et d’une liste d’arguments vides. 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 une classe, un struct ou un type d’interface, une erreur est générée et aucune autre étape n’est effectuée.- La recherche de membre est effectuée sur
E
avec l’identificateurCurrent
et aucun argument de type. Si la recherche de membre ne produit aucune correspondance, le résultat est une erreur ou le résultat est autre chose qu’une propriété d’instance publique qui autorise la lecture, une erreur est générée et aucune autre étape n’est effectuée.- La recherche de membre est effectuée sur
E
avec l’identificateurMoveNext
et aucun argument de type. Si la recherche de membre ne produit aucune correspondance, le résultat est une erreur ou le résultat est autre chose qu’un groupe de méthodes, une erreur est générée et aucune autre étape n’est effectuée.- 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 ne génère aucune méthode applicable, génère une ambiguïté ou génère une méthode optimale, mais cette méthode est statique ou non publique, ou son type de retour n’est pas
bool
, une erreur est générée et aucune autre étape n’est effectuée.- Le type de collection
est , le type d’énumérateur est , et le type d’élément est le type de la propriété . 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 type uniqueT
de sorte queT
n’est pasdynamic
et pour tous les autresTi
il existe une conversion implicite deIEnumerable<T>
enIEnumerable<Ti>
, le type de collection est laIEnumerable<T>
d’interface , le type d’énumérateur est l’interfaceIEnumerator<T>
, et le type d’élément estT
.- Sinon, s’il existe plusieurs types de ce type
T
, une erreur est générée et aucune autre étape n’est effectuée.- 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' a 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 membre ne produit pas de correspondance, ou qu’elle génère une ambiguïté ou produit une correspondance qui n’est pas un groupe de méthodes, une erreur est générée et aucune autre étape n’est effectuée. 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 une résolution de surcharge à l’aide du groupe de méthodes résultant et d’un seul argument de type
X
. Si la résolution de surcharge ne produit aucune méthode applicable, génère une ambiguïté ou génère une seule méthode optimale, mais cette méthode n’est pas accessible, une erreur est générée sans aucune autre étape.
- Cette résolution permet au premier argument d’être passé par ref si
X
est un type de struct, et que le type ref estin
.- Si le type de retour
E
de la méthodeGetEnumerator
n’est pas une classe, un struct ou un type d’interface, une erreur est générée et aucune autre étape n’est effectuée.- La recherche de membre est effectuée sur
E
avec l’identificateurCurrent
et aucun argument de type. Si la recherche de membre ne produit aucune correspondance, le résultat est une erreur ou le résultat est autre chose qu’une propriété d’instance publique qui autorise la lecture, une erreur est générée et aucune autre étape n’est effectuée.- La recherche de membre est effectuée sur
E
avec l’identificateurMoveNext
et aucun argument de type. Si la recherche de membre ne produit aucune correspondance, le résultat est une erreur ou le résultat est autre chose qu’un groupe de méthodes, une erreur est générée et aucune autre étape n’est effectuée.- 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 ne génère aucune méthode applicable, génère une ambiguïté ou génère une méthode optimale, mais cette méthode est statique ou non publique, ou son type de retour n’est pas
bool
, une erreur est générée et aucune autre étape n’est effectuée.- Le type de collection
est , le type d’énumérateur est , et le type d’élément est le type de la propriété . Sinon, une erreur est générée et aucune autre procédure n’est effectuée.
Pour await foreach
, les règles sont modifiées de la même façon. La seule modification nécessaire à cette spécification supprime 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 substitués aux méthodes de modèle.
Inconvénients
Chaque modification ajoute une complexité supplémentaire à la langue, ce qui permet potentiellement aux éléments qui n’ont pas été conçus pour être foreach
ed d’être foreach
ed, comme Range
.
Alternatives
Ne rien faire.
Questions non résolues
Aucun à ce stade.
C# feature specifications