Partager via


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 avec ce texte :

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 de X vers l’interface de IEnumerable (étant donné que System.Array implémente cette interface). Le type de collection est l’interface IEnumerable, le type d’énumérateur est l’interface IEnumerator et le type d’élément est le type d’élément du type de tableau X.

  • Si le type X de expression est dynamic il existe une conversion implicite de expression vers l’interface de IEnumerable (§10.2.10). Le type de collection est l’interface IEnumerable et le type d’énumérateur est l’interface IEnumerator. Si l’identificateur var est donné en tant que local_variable_type, le type d’élément est dynamic, sinon il est object.

  • Sinon, déterminez si le type X a une méthode GetEnumerator appropriée :

    • Effectuer une recherche de membre sur le type X avec l'identifiant GetEnumerator 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éthode GetEnumerator 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’identificateur Current 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’identificateur MoveNext 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 de X en IEnumerable<Ti>, il existe un type unique T de sorte que T n’est pas dynamic et pour tous les autres Ti il existe une conversion implicite de IEnumerable<T> en IEnumerable<Ti>, le type de collection est la IEnumerable<T>d’interface , le type d’énumérateur est l’interface IEnumerator<T>, et le type d’élément est T.
    • 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’interface System.Collections.IEnumerable, le type de collection est cette interface, le type d’énumérateur est l’interface System.Collections.IEnumeratoret le type d’élément est object.
  • 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'identifiant GetEnumerator. 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 est in.
    • Si le type de retour E de la méthode GetEnumerator 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’identificateur Current 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’identificateur MoveNext 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 foreached d’être foreached, comme Range.

Alternatives

Ne rien faire.

Questions non résolues

Aucun à ce stade.