getenumerator - ienumerable c# foreach
¿Foreach puede lanzar InvalidCastException? (3)
Imagine el siguiente código:
class foreach_convert
{
public static void method2()
{
List<IComparable> x = new List<IComparable>();
x.Add(5);
foreach (string s in x)
{
//InvalidCastException in runtime
}
}
}
Me pregunto, ¿por qué es este comportamiento foreach tan ... no como C #? Lo que sucede aquí es un lanzamiento implícito a una subclase, que es propensa a errores y parece estar prohibida en cualquier otro lugar del idioma. ¿O no estoy en lo cierto?
PD: La razón por la que estoy preguntando es que tenía un error en el código similar en mi proyecto, donde solía iterar a través de una colección personalizada desde una biblioteca externa, que se llamaba SomeTypeCollection
, pero de hecho proporcionaba una colección de tipo base. artículos y podría haber contenido artículos de SomeOtherType
. Es mi culpa, pero ni el lenguaje ni el compilador proporcionaron consejos / advertencias explícitos, lo cual es bastante inusual para C # ...
Con C # 3 estoy usando var , así que recibo las advertencias del compilador.
Recuerde antes de los genéricos ... foreach
tuvo que emitir para que pueda hacer cosas sensatas como:
foreach (string x in names)
{
// ...
}
en lugar de:
foreach (object tmp in names)
{
string x = (string) tmp;
// ...
}
El último es simplemente asqueroso, IMO. Proporcionar un elenco implícito es diferente del resto del lenguaje, pero lo hace mucho más fácil de usar en la gran mayoría de los casos.
Sospecho que si C # tuviera genéricos y métodos de extensión para empezar (para poder usar OfType
y Cast
) ese foreach
no se especificaría de la misma manera.
Tenga en cuenta que hay aún más rarezas en foreach
: el tipo no tiene que implementar IEnumerable
en absoluto. Siempre que tenga un método GetEnumerator
que devuelva algo que a su vez tenga MoveNext()
y Current
, el compilador de C # estará contento. Esto significaba que podía implementar un "iterador fuertemente tipado" (para evitar el boxeo) antes de los genéricos.
foreach funciona en IEnumerable, que devuelve objetos de tipo objeto . Para cada elemento, el objeto será lanzado al tipo que proporcionó.
A menos que use var en C # 3.0. Entonces el tipo será tomado de IEnumerable<T>
, si es implementado por la colección.