Qual è il modo migliore per convertire un IEnumerator in un IEnumerator generico?
-
06-07-2019 - |
Domanda
Sto scrivendo un ConfigurationElementCollection personalizzato per un ConfigurationHandler personalizzato in C # .NET 3.5 e desidero esporre IEnumerator come IEnumerator generico.
Quale sarebbe il modo migliore per raggiungere questo obiettivo?
Attualmente sto usando il codice:
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(); }
Saluti
Soluzione
Non credo ci sia nulla nel framework, ma potresti facilmente scriverne uno:
IEnumerator<T> Cast<T>(IEnumerator iterator)
{
while (iterator.MoveNext())
{
yield return (T) iterator.Current;
}
}
È allettante chiamare Enumerable.Cast<T>
da LINQ e quindi chiamare GetEnumerator()
sul risultato, ma se la tua classe implementa già IEnumerable<T>
e T
è un tipo di valore, che funge da no-op, quindi la StackOverflowException
chiama recruit e genera un return foo.Cast<T>.GetEnumerator();
. È sicuro usare foo
quando <=> è sicuramente un oggetto diverso (che non è delegato a questo) ma per il resto, probabilmente è meglio usare il codice sopra.
Altri suggerimenti
IEnumerable<T>
deriva già da IEnumerable
quindi non è necessario eseguire alcuna conversione. Puoi semplicemente lanciarlo ... beh, in realtà non è implicito il cast necessario.
IEnumerable<T> enumerable = GetGenericFromSomewhere();
IEnumerable sadOldEnumerable = enumerable;
return sadOldEnumerable.GetEnumerator();
Fare il contrario non è molto più difficile con LINQ:
var fancyEnumerable = list.OfType<GenericObject>();
return fancyEnumerable.GetEnumerator();
Stavo riscontrando lo stesso problema di overflow dello stack menzionato in alcuni dei commenti. Nel mio caso è stato dovuto al fatto che la chiamata GetEnumerator doveva essere sulla base.GetEnumerator altrimenti esegui il ciclo all'interno della tua ridefinizione di GetEnumerator.
Questo è il codice che stava lanciando lo Stack Overflow. L'uso dell'istruzione foreach chiama la stessa funzione GetEnumerator che sto cercando di sovraccaricare:
public new IEnumerator<T> GetEnumerator()
{
foreach (T type in this)
{
yield return type;
}
}
Ho finito con una versione semplificata del post originale in quanto non è necessario utilizzare un proprietario di elenco.
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;
}
}
...
}
Puoi usare OfType<T>
e 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);
Per ottenere un IEnumerator<T>
anziché un IEnumerable<T>
puoi semplicemente effettuare una chiamata a GetEnumerator()
var enumerator = Digits().OfType<int>().GetEnumerator();
Questo funziona per me.
IEnumerator<DataColumn> columnEnumerator = dt.Columns.Cast<DataColumn>().GetEnumerator();