将IEnumerator转换为通用IEnumerator的最佳方法是什么?
-
06-07-2019 - |
题
我正在为C#.NET 3.5中的自定义ConfigurationHandler编写自定义ConfigurationElementCollection,并且我希望将IEnumerator公开为通用IEnumerator。
实现这一目标的最佳方式是什么?
我目前正在使用代码:
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(); }
干杯
解决方案
我不相信框架中有任何内容,但您可以轻松地编写一个:
IEnumerator<T> Cast<T>(IEnumerator iterator)
{
while (iterator.MoveNext())
{
yield return (T) iterator.Current;
}
}
从LINQ调用Enumerable.Cast<T>
然后在结果上调用GetEnumerator()
是很诱人的 - 但是如果你的类已经实现了IEnumerable<T>
并且T
是一个值类型,那么它就像一个no-op,所以StackOverflowException
调用recurses并抛出return foo.Cast<T>.GetEnumerator();
。当foo
肯定是不同的对象(它不会委托给它)时,使用<=>是安全的,但除此之外,你可能最好使用上面的代码。
其他提示
IEnumerable<T>
已经从IEnumerable
派生,因此无需进行任何转换。你可以简单地投射到它......实际上它是暗示没有必要的演员。
IEnumerable<T> enumerable = GetGenericFromSomewhere();
IEnumerable sadOldEnumerable = enumerable;
return sadOldEnumerable.GetEnumerator();
对于LINQ来说,反过来并不困难:
var fancyEnumerable = list.OfType<GenericObject>();
return fancyEnumerable.GetEnumerator();
我遇到了同样的Stack Overflow问题,提到了一些评论。在我的情况下,这是因为GetEnumerator调用需要到base.GetEnumerator,否则你在你自己的GetEnumerator重新定义中循环。
这是抛出堆栈溢出的代码。使用foreach语句调用我试图重载的相同GetEnumerator函数:
public new IEnumerator<T> GetEnumerator()
{
foreach (T type in this)
{
yield return type;
}
}
我最终得到了原始帖子的简化版本,因为您不需要使用列表持有者。
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;
}
}
...
}
您可以使用OfType<T>
和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);
要获得IEnumerator<T>
而非IEnumerable<T>
,您只需拨打GetEnumerator()
var enumerator = Digits().OfType<int>().GetEnumerator();
这适合我。
IEnumerator<DataColumn> columnEnumerator = dt.Columns.Cast<DataColumn>().GetEnumerator();