¿Cuál es la mejor manera de convertir un IEnumerator en un IEnumerator genérico?
-
06-07-2019 - |
Pregunta
Estoy escribiendo una ConfigurationElementCollection personalizada para un ConfigurationHandler personalizado en C#.NET 3.5 y quiero exponer el IEnumerator como un IEnumerator genérico.
¿Cuál sería la mejor manera de lograrlo?
Actualmente estoy usando el código:
public new IEnumerator<GenericObject> GetEnumerator() { var list = new List(); var baseEnum = base.GetEnumerator(); while(baseEnum.MoveNext()) { var obj = baseEnum.Current as GenericObject; if (obj != null) list.Add(obj); } return list.GetEnumerator(); }
Salud
Solución
No creo que haya nada en el marco, pero fácilmente podrías escribir uno:
IEnumerator<T> Cast<T>(IEnumerator iterator)
{
while (iterator.MoveNext())
{
yield return (T) iterator.Current;
}
}
Es tentador simplemente llamar Enumerable.Cast<T>
desde LINQ y luego llamar GetEnumerator()
en el resultado - pero si su clase ya implementa IEnumerable<T>
y T
es un tipo de valor que actúa como no operativo, por lo que el GetEnumerator()
llama recursivamente y lanza un StackOverflowException
.Es seguro de usar return foo.Cast<T>.GetEnumerator();
cuando foo
es definitivamente un diferente object (que no delega a este) pero, de lo contrario, probablemente sea mejor que utilices el código anterior.
Otros consejos
IEnumerable<T>
ya se deriva de IEnumerable
, por lo que no es necesario realizar ninguna conversión. Simplemente puede lanzarlo ... bueno, en realidad es implícito, no es necesario lanzarlo.
IEnumerable<T> enumerable = GetGenericFromSomewhere();
IEnumerable sadOldEnumerable = enumerable;
return sadOldEnumerable.GetEnumerator();
Ir al revés no es mucho más difícil con LINQ:
var fancyEnumerable = list.OfType<GenericObject>();
return fancyEnumerable.GetEnumerator();
Me encontraba con el mismo problema de desbordamiento de pila mencionado en algunos de los comentarios. En mi caso, se debió al hecho de que la llamada GetEnumerator tenía que ser a la base. GetEnumerator, de lo contrario, se repite dentro de su propia redefinición GetEnumerator.
Este es el código que arrojó el desbordamiento de pila. El uso de la instrucción foreach llama a la misma función GetEnumerator que intento sobrecargar:
public new IEnumerator<T> GetEnumerator()
{
foreach (T type in this)
{
yield return type;
}
}
Terminé con una versión simplificada de la publicación original, ya que no es necesario utilizar un titular de la Lista.
public class ElementCollection<T> : ConfigurationElementCollection, IList<T>
...
public new IEnumerator<T> GetEnumerator()
{
var baseEnum = base.GetEnumerator();
while (baseEnum.MoveNext())
{
yield return baseEnum.Current as T;
}
}
...
}
Puedes usar OfType<T>
y Cast<T>
.
public static IEnumerable Digits()
{
return new[]{1, 15, 68, 1235, 12390, 1239};
}
var enumerable = Digits().OfType<int>();
foreach (var item in enumerable)
// var is here an int. Without the OfType<int(), it would be an object
Console.WriteLine(i);
para conseguir un IEnumerator<T>
en lugar de un IEnumerable<T>
puedes simplemente hacer una llamada a GetEnumerator()
var enumerator = Digits().OfType<int>().GetEnumerator();
Esto funciona para mí.
IEnumerator<DataColumn> columnEnumerator = dt.Columns.Cast<DataColumn>().GetEnumerator();