相当于无数<t>无损失</t>

时间:2014-10-16 09:14:50

标签: c# linq

我有一个只接受ienumerable<t>参数的方法,但我的本地值是一个简单的可数字。

我无法改变这些条件。

现在我的问题是如何在不丢失项目的对象引用的情况下获得ienumerable<t>的数据?我不想复制数据或其他任何内容。

ienumerable.Cast<object>()能完成这项工作吗?我不希望新项目的引用我只想尽可能快地获得ienumerable<t>

3 个答案:

答案 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>,如果源中的任何项目无法转换为TEnumerable.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);