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

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 de X vers l'interface IEnumerable (puisque 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 l'expression est dynamic, il y a une conversion implicite de l'expression vers l'interface 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é comme type de variable locale, le type de l'élément et dynamic, sinon il est object.

  • Sinon, déterminez si le type X possède 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 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éthode GetEnumerator 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'identifiant Current 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'identifiant MoveNext 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 est E 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 de X en IEnumerable<Ti>, il existe un type T unique tel que T n'est pas dynamic et que, pour tous les autres Ti, il existe une conversion implicite de IEnumerable<T> en IEnumerable<Ti>, alors le type de collection est l'interface IEnumerable<T>, le type d'énumérateur est l'interface IEnumerator<T> et le type d'élément est T.
    • 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'interface System.Collections.IEnumerable, le type de collection est cette interface, le type d'énumérateur est l'interface System.Collections.IEnumerator et le type d'élément est object.
  • 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'identifiant GetEnumerator. 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 est in.
    • Si le type de retour E de la méthode GetEnumerator 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'identifiant Current 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'identifiant MoveNext 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 est E 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.