static void Main(string[] args)
{
List<int> listArray = new List<int>();
listArray.Add(100);
foreach (int item in listArray)
Console.WriteLine(item);
}
a) Cuando foreach
declaración pide listArray's IEnumerable<int>.GetEnumerator()
aplicación, no se llaman a través de listArray.GetEnumerator()
o IEnumerable<int>.GetEnumerator()
o IEnumerable.GetEnumerator()
?¿Cómo llama foreach a GetEnumerator()? ¿A través de la referencia de IEnumerable o vía ...?
b) Del mismo modo, cuando foreach
referencias objeto devuelto por listArray's IEnumerable<int>.GetEnumerator()
, ¿se Referencia este objeto a través de IEnumerator
o IEnumerator<int>
tipo de referencia?
gracias
EDIT:
Algunos de mis preguntas van a citar el texto:
o realizar la búsqueda de miembro del tipo X con GetEnumerator identificador y no hay argumentos de tipo . Si la búsqueda de miembro no produce una coincidencia, o produce una ambigüedad, o produce una coincidencia que no es un grupo de métodos, compruebe si hay una interfaz enumerable como que se describe a continuación. Se recomienda que se emita una advertencia si la búsqueda del miembro produce algo excepto un grupo de métodos o no coincide.
o Realice la resolución de sobrecarga usando el grupo de métodos resultante y una lista de argumentos vacíos . Si la sobrecarga de resultados resolución en ningún métodos aplicables, resulta en una ambigüedad, o resultados en un único mejor método pero que el método es o bien estática o no público, comprobar para una interfaz enumerable como se describe a continuación. Es recomendado que se emita una advertencia si la resolución de sobrecarga produce cualquier cosa excepto un método de instancia público inequívoco o ningún método aplicable .
o Si el tipo de retorno del método E GetEnumerator no es una clase, estructura o tipo de interfaz, un error es producido y no hay nuevas medidas son tomadas .
o La búsqueda de miembros se realiza en E con el identificador Current y no escribe argumentos. Si la búsqueda de miembro no produce coincidencias, el resultado es un error , o el resultado es cualquier cosa excepto una propiedad de instancia pública que permite leer, se produce un error y no se realizan más pasos.
o La búsqueda de miembros se realiza en E con con el identificador MoveNext y sin argumentos de tipo . Si la búsqueda de miembro no produce coincidencias, el resultado es un error , o el resultado es cualquier cosa excepto un grupo de métodos, se produce un error y no se realizan más pasos .
o 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 la sobrecarga que no resulta en los métodos aplicables, resultados en una ambigüedad, o resultados en un mejor método, pero ese método es estática o no pública, o su tipo retorno no es BOOL, un error es producido y no hay más pasos son tomado.
o El tipo de colección es X, el tipo empadronador es E, y el tipo de elemento es el tipo de la propiedad Current .
De lo contrario, compruebe si hay una interfaz enumerables: o Si hay exactamente un tipo T de tal manera que hay una implícita la conversión de X a la interfaz System.Collections.Generic.IEnumerable, entonces la colección tipo es esta interfaz , el tipo empadronador es la interfaz System.Collections.Generic.IEnumerator, y el tipo de elemento es T.
de lo contrario, si hay más de un tipo tal T, entonces se produce un error y no se toman más pasos .
De lo contrario, si hay una conversión implícita de X a la interfaz System.Collections.IEnumerable , entonces el tipo de recogida es esta interfaz, el tipo empadronador es la interfaz System.Collections.IEnumerator, y el tipo de elemento es objeto.
De lo contrario, se produce un error y no se realizan más pasos .
1)
Presupuesto de Eric Lippert:
Opción (1) es correcta. Tenga en cuenta que este significa que el enumerador devuelto es una estructura mutable sin caja.
El hecho de que esta es una estructura mutable tiene efectos muy reales si lo hace algo tonto como pasar alrededor la estructura como si se tratara de un tipo de referencia; se copiará por el valor , no por referencia.
De http://en.csharp-online.net/ECMA-334:_15.8.4_The_foreach_statement:
foreach (V v en x)-instrucción incrustada
continuación se expande a:
{ E e = ((C)(x)).GetEnumerator(); try { V v; while (e.MoveNext()) { v = (V)(T)e.Current; embedded-statement } } finally { … // Dispose e } }
La variable e no es visible para o accesible para la expresión x o la declaración incrustada o cualquier otra fuente código del programa.
En caso de listArray
, el empadronador devuelto se guarda (es decir, su valor se guarda) en la variable e
(por lo tanto variable de e
es un struct mutable) .Pero de acuerdo con el extracto anterior, e
no es accesible a mi fuente código, entonces, ¿cómo podría pasar esta estructura (a menos que escriba el código que hace manualmente lo que foreach
declaración hace automáticamente)?
2)
de búsqueda Miembro se realiza en E con el identificador actual y no hay argumentos de tipo. Si la búsqueda de miembro no produce coincidencias, el resultado es un error, o el resultado es cualquier cosa excepto una propiedad de instancia pública que permite la lectura, se produce un error y no se toman pasos adicionales.
Parece que si ponemos en práctica GetEnumerator
en la clase (X
) en sí, entonces Current
debería también ser implementado en la clase (E
) sí (por lo tanto E
no debe poner en práctica de manera explícita Current
), ya que el compilador no lo hará molestarse en verificar las interfaces IEnumerator<T>/IEnumerator
en los casos en que la búsqueda de miembros (en E
con el identificador Current
) no produce una coincidencia?
3)
Si hay exactamente un tipo T tal que hay una conversión implícita de X a la System.Collections.Generic.IEnumerable interfaz, entonces el tipo de colección es esta interfaz , la tipo empadronador es la System.Collections.Generic.IEnumerator interfaz , y el tipo de elemento es T.
de acuerdo con lo anterior, si foreach
que verificar para IEnumerable<T>
interfaz, entonces foreach
siempre usará IEnumerator<T>
versión de Current
? Por lo tanto, si se implementa de forma explícita E
IEnumerator<T>
versión de Current
y si se implementa también otra versión de Current
en la propia clase, el foreach
siempre llamar la versión de IEnumerable<T>
Current
?
4)
El método GetEnumerator se documenta como entrega de uno de estos:
¿Qué quiere decir por uno de estos (como en plural)? El enlace que proporcionó dice GetEnumerator
(implementado por List<T>
) solo devuelve struct
tipo.
5)
g. El tipo de colección es X, el tipo enumerador es E, y el tipo de elemento es el tipo de la propiedad actual
Quizás una pregunta inútil - acuerdo con lo anterior, foreach
no comprueba qué tipo de elementos de algunos por el usuario colección definida realmente almacena, pero en su lugar asume que el tipo de elementos es el mismo que el tipo devuelto por la propiedad Current
?
¿Has considerado escribir una prueba simple para descubrirlo? Sería bastante trivial escribir una clase que implemente 'IEnumerable.GetEnumerator()' y GetEnumerator() y que devuelva diferentes enumeradores. – Aren
He actualizado mi respuesta para abordar sus preguntas adicionales. –