Compartir vía


Compatibilidad con extensiones GetEnumerator para bucles foreach.

Nota

Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos e se incorporan en la especificación ECMA actual.

Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.

Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C# en el artículo sobre las especificaciones de .

Resumen

Permite que los bucles foreach reconozcan un método de extensión GetEnumerator que, de otra manera, cumpliría con el patrón foreach, y que recorran en bucle la expresión cuando de lo contrario sería un error.

Motivación

Esto incorporará foreach en línea con la forma en que se implementan otras características de C#, incluida la deconstrucción asincrónica y basada en patrones.

Diseño detallado

El cambio de especificación es relativamente sencillo. Hemos modificado la sección The foreach statement§13.9.5 a este texto:

El procesamiento en tiempo de compilación de una instrucción foreach primero determina el tipo de colección , el tipo de enumerador y el tipo de elemento de la expresión. Esta determinación continúa de la siguiente manera:

  • Si el tipo X de expresión es un tipo de matriz, hay una conversión de referencia implícita de X a la interfaz IEnumerable (ya que System.Array implementa esta interfaz). El tipo de colección es la interfaz IEnumerable, el tipo de enumerador es la interfaz IEnumerator y el tipo de elemento es el tipo de elemento del tipo de matriz X.

  • Si el tipo X de expresión es dynamic, hay una conversión implícita de expresión a la interfaz de IEnumerable (§10.2.10). El tipo de colección es la interfaz IEnumerable y el tipo de enumerador es la interfaz IEnumerator. Si el identificador de var se proporciona como local_variable_type, el tipo de elemento es dynamic, de lo contrario, es object.

  • De lo contrario, determine si el tipo X tiene un método GetEnumerator adecuado:

    • Haga una búsqueda de miembros en el tipo X con el identificador GetEnumerator y sin argumentos de tipo. Si la búsqueda de miembros no produce una coincidencia, o genera una ambigüedad, o genera una coincidencia que no es un grupo de métodos, compruebe si hay una interfaz enumerable como se describe a continuación. Se recomienda emitir una advertencia si la búsqueda de miembros genera cualquier cosa excepto un grupo de métodos o ninguna coincidencia.
    • Realice la resolución de sobrecargas mediante el grupo de métodos resultante y una lista de argumentos vacía. Si la resolución de sobrecargas no da lugar a ningún método aplicable, da como resultado una ambigüedad o da como resultado un único método mejor, pero ese método es estático o no público, compruebe si hay una interfaz enumerable como se describe a continuación. Se recomienda emitir una advertencia si la resolución de sobrecarga genera cualquier cosa excepto un método de instancia inequívoco y público o ningún método aplicable.
    • Si el tipo de valor devuelto E del método GetEnumerator no es una clase, estructura o tipo de interfaz, se produce un error y no se realizan más pasos.
    • La búsqueda de miembros se realiza en E con el identificador Current y sin argumentos de tipo. Si la búsqueda de miembros no produce ninguna coincidencia, el resultado es un error o el resultado es cualquier cosa excepto una propiedad de instancia pública que permita la lectura, se produce un error y no se realizan más pasos.
    • La búsqueda de miembros se realiza en E con el identificador MoveNext y sin argumentos de tipo. Si la búsqueda de miembros no produce ninguna coincidencia, el resultado es un error o el resultado es cualquier cosa excepto un grupo de métodos, se genera un error y no se realizan más pasos.
    • La resolución de sobrecarga se realiza en el grupo de métodos con una lista de argumentos vacía. Si la resolución de sobrecarga no da lugar a ningún método aplicable, da como resultado una ambigüedad o da como resultado un único método mejor, pero ese método es estático o no público, o su tipo de valor devuelto no es bool, se produce un error y no se realizan pasos adicionales.
    • El tipo de colección es X, el tipo de enumerador es Ey el tipo de elemento es el tipo de la propiedad Current.
  • De lo contrario, compruebe si hay una interfaz enumerable:

    • Si entre todos los tipos Ti para los que hay una conversión implícita de X a IEnumerable<Ti>, hay un tipo único T de modo que T no es dynamic y para el resto de Ti hay una conversión implícita de IEnumerable<T> a IEnumerable<Ti>, el tipo de colección es la IEnumerable<T>interfaz , , el tipo de enumerador es la interfaz IEnumerator<T>y el tipo de elemento es T.
    • De lo contrario, si hay más de un tipo de este tipo T, se produce un error y no se realizan pasos adicionales.
    • De lo contrario, si hay una conversión implícita de X a la interfaz de System.Collections.IEnumerable, el tipo de colección es esta interfaz, el tipo de enumerador es la interfaz System.Collections.IEnumeratory el tipo de elemento es object.
  • De lo contrario, determine si el tipo "X" tiene un método de extensión GetEnumerator adecuado:

    • Realice la búsqueda de métodos de extensión en el tipo X con identificador GetEnumerator. Si la búsqueda de miembros no produce una coincidencia, o genera una ambigüedad, o genera una coincidencia que no es un grupo de métodos, se produce un error y no se realizan pasos adicionales. Se recomienda emitir una advertencia si la búsqueda de miembros produce algo distinto a un grupo de métodos o cuando no haya coincidencias.
    • Realice la resolución de sobrecarga mediante el grupo de métodos resultante y un único argumento de tipo X. Si la resolución de sobrecarga no genera ningún método aplicable, da como resultado una ambigüedad o da como resultado un único método mejor, pero ese método no es accesible, se produce un error que no se realiza ningún paso adicional.
      • Esta resolución permite pasar el primer argumento por ref si X es un tipo de estructura y el tipo ref es in.
    • Si el tipo de valor devuelto E del método GetEnumerator no es una clase, estructura o tipo de interfaz, se produce un error y no se realizan más pasos.
    • La búsqueda de miembros se realiza en E con el identificador Current y sin argumentos de tipo. Si la búsqueda de miembros no produce ninguna coincidencia, el resultado es un error o el resultado es cualquier cosa excepto una propiedad de instancia pública que permita la lectura, se produce un error y no se realizan más pasos.
    • La búsqueda de miembros se realiza en E con el identificador MoveNext y sin argumentos de tipo. Si la búsqueda de miembros no produce ninguna coincidencia, el resultado es un error o el resultado es cualquier cosa excepto un grupo de métodos, se genera un error y no se realizan más pasos.
    • La resolución de sobrecarga se realiza en el grupo de métodos con una lista de argumentos vacía. Si la resolución de sobrecarga no da lugar a ningún método aplicable, da como resultado una ambigüedad o da como resultado un único método mejor, pero ese método es estático o no público, o su tipo de valor devuelto no es bool, se produce un error y no se realizan pasos adicionales.
    • El tipo de colección es X, el tipo de enumerador es Ey el tipo de elemento es el tipo de la propiedad Current.
  • De lo contrario, se produce un error y no se realizan pasos adicionales.

Para await foreach, las reglas se modifican de forma similar. El único cambio necesario para esa especificación es quitar la línea Extension methods do not contribute. de la descripción, ya que el resto de esa especificación se basa en las reglas anteriores con nombres diferentes sustituidos por los métodos de patrón.

Inconvenientes

Cada cambio agrega complejidad adicional al lenguaje, y esto potencialmente permite que lo que se diseñó para tener foreach tenga foreach, como Range.

Alternativas

Sin hacer nada.

Preguntas sin resolver

Ninguno en este momento.