我有一个只接受ienumerable<t>
参数的方法,但我的本地值是一个简单的可数字。
我无法改变这些条件。
现在我的问题是如何在不丢失项目的对象引用的情况下获得ienumerable<t>
的数据?我不想复制数据或其他任何内容。
ienumerable.Cast<object>()
能完成这项工作吗?我不希望新项目的引用我只想尽可能快地获得ienumerable<t>
。
答案 0 :(得分:6)
Linq-Statement只是一组规则,当有人从IEnumerable请求linq语句生成的项时执行这些规则。 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查询,请仅使用这些方法。
答案 1 :(得分:2)
为此目的有两种linq方法:Enumerable.Cast<T>
,如果源中的任何项目无法转换为T
或Enumerable.OfType<T>
,则会抛出异常,这将跳过元素在没有抛出的情况下无法强制转换为T
,但速度有点慢,因为它会检查每个元素的类型(Enumerable.Cast<T>
只是将其强制转换为T
)。
答案 2 :(得分:1)
作为补充答案,除了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);