ienumerable到ienumerable<;t>;没有损失
本文关键字:ienumerable 损失 gt lt | 更新日期: 2023-09-27 18:26:47
我有一个只接受ienumerable<t>
参数的方法,但我的局部值是一个简单的整数。
我无法改变这些条件。
现在我的问题是如何在不丢失项的对象引用的情况下获得对ienumerable<t>
的枚举?我不想复制数据或其他什么。
ienumerable.Cast<object>()
能胜任这项工作吗?我不想要新的项目参考,我只想尽快从ienumerable获得ienumerable<t>
。
Linq语句只是一组规则,当有人从Linq语句生成的IEnumerable中请求项时执行这些规则。foreach就是这样一个消费者,但IEnumerable的任何其他消费者在获得物品之前都会启动相同的规则,所以你总是可以把foreach想象成一个类比。
foreach(object item in myEnumerable)
{
((MyClass)item).DoSomething();
}
在概念上与相同
foreach(MyClass item in myEnumerable.Cast<MyClass>())
{
item.DoSomething();
}
所以没有,没有复制。但是,如果您尝试强制转换错误类型的项,它应该会抛出错误。如果你想要更多这样的东西:
foreach(object item in myEnumerable)
{
MyClass myItem = item as MyClass;
if(myItem != null)
myItem.DoSomething();
}
那么您将使用OfType():
foreach(MyClass item in myEnumerable.OfType<MyClass>())
{
item.DoSomething();
}
请注意,如果您对可枚举对象调用ToList或ToArray,它将由您自己进行求值(发生的情况与调用foreach时相同),并将其保存到新集合中。如果您的原始IEnumerable包含值类型(如int、float、structs等),而不是引用类型(如您自己的任何类),那么您实际上会在新数组中拥有项的副本。因此,只有当您真正想尽早评估linq查询时,才可以使用这些方法。
有两种linq方法可用于此目的:Enumerable.Cast<T>
,如果源中的任何项无法强制转换为T
,它将抛出异常;Enumerable.OfType<T>
,它将跳过无法强制转换到T
而不抛出的元素,但速度稍慢,因为它检查每个元素的类型(Enumerable.Cast<T>
只是将其强制转换为T
)。
作为一个补充答案,除了Cast<T>
和OfType<T>
扩展方法外,您还可以手动实现它(对于较旧的框架或像unity3d这样的嵌入式框架更有用)
using System;
using System.Collections;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public class WrapperEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerable _enumerable;
public IEnumerator<T> GetEnumerator()
{
return new WrapperEnumerator<T>(_enumerable.GetEnumerator());
}
IEnumerator IEnumerable.GetEnumerator()
{
return _enumerable.GetEnumerator();
}
public WrapperEnumerable(IEnumerable enumerable)
{
_enumerable = enumerable;
}
}
public class WrapperEnumerator<T>:IEnumerator<T>
{
private readonly IEnumerator _enumerator;
public T Current
{
get { return (T)Convert.ChangeType(_enumerator.Current,typeof(T)); }
}
public void Dispose()
{
}
object IEnumerator.Current
{
get { return _enumerator.Current; }
}
public bool MoveNext()
{
return _enumerator.MoveNext();
}
public void Reset()
{
_enumerator.Reset();
}
public WrapperEnumerator(IEnumerator enumerator)
{
_enumerator = enumerator;
}
}
}
使用情况类似
var list = new ArrayList {1, 2, 3};
foreach(var n in new WrapperEnumerable<int>(list))
Console.WriteLine(n);
//using Cast method extension
foreach (var n in list.Cast<int>())
Console.WriteLine(n);
//using OfType method extension
foreach(var n in list.OfType<int>())
Console.WriteLine(n);