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 deX
a la interfazIEnumerable
(ya queSystem.Array
implementa esta interfaz). El tipo de colección es la interfazIEnumerable
, el tipo de enumerador es la interfazIEnumerator
y el tipo de elemento es el tipo de elemento del tipo de matrizX
.Si el tipo
X
de expresión esdynamic
, hay una conversión implícita de expresión a la interfaz deIEnumerable
(§10.2.10). El tipo de colección es la interfazIEnumerable
y el tipo de enumerador es la interfazIEnumerator
. Si el identificador devar
se proporciona como local_variable_type, el tipo de elemento esdynamic
, de lo contrario, esobject
.De lo contrario, determine si el tipo
X
tiene un métodoGetEnumerator
adecuado:
- Haga una búsqueda de miembros en el tipo
X
con el identificadorGetEnumerator
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étodoGetEnumerator
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 identificadorCurrent
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 identificadorMoveNext
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 esE
y el tipo de elemento es el tipo de la propiedadCurrent
.De lo contrario, compruebe si hay una interfaz enumerable:
- Si entre todos los tipos
Ti
para los que hay una conversión implícita deX
aIEnumerable<Ti>
, hay un tipo únicoT
de modo queT
no esdynamic
y para el resto deTi
hay una conversión implícita deIEnumerable<T>
aIEnumerable<Ti>
, el tipo de colección es laIEnumerable<T>
interfaz , , el tipo de enumerador es la interfazIEnumerator<T>
y el tipo de elemento esT
.- 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 deSystem.Collections.IEnumerable
, el tipo de colección es esta interfaz, el tipo de enumerador es la interfazSystem.Collections.IEnumerator
y el tipo de elemento esobject
.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 identificadorGetEnumerator
. 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 esin
.- Si el tipo de valor devuelto
E
del métodoGetEnumerator
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 identificadorCurrent
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 identificadorMoveNext
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 esE
y el tipo de elemento es el tipo de la propiedadCurrent
.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.
C# feature specifications