我有以下代码

class Program
    {
        static void Main(string[] args)
        {
            List<A> aList = new List<A>();

            var aObj = new A();

            aObj.Go(aList.Cast<IB>());
        }
    }

    class A : IB
    {
        public void Go(IEnumerable<IB> interfaceList)
        {
            foreach (IB ibby in interfaceList)
            {
                Console.WriteLine("Here");
            }
        }
    }

    interface IB
    {
        void Go(IEnumerable<IB> interfaceList);
    }

}

我最初尝试传递一个List但是不起作用。 在所以的大量帮助后,我发现通过IEnumerable是唯一的方法是将对象作为.ofType(IB)。

不幸的是,在我的代码中,以下行将被执行数千次:

aList.Cast<IB>();

我想知道是否有人知道它是如何通过算法实现的(在IL中)以及它的时间顺序是什么。

也就是说,它是否比仅仅投射每个项目的foreach循环更快,还是正是它所做的那样?

编辑主类需要维护实际对象的列表。但是只允许读者通过界面触摸它们。

有帮助吗?

解决方案

您应该将 Go 更改为:

public void Go<T>(IEnumerable<T> interfaceList)
    where T : IB
{
    foreach (IB ibby in interfaceList)
    {
        Console.WriteLine("Here");
    }
}

然后你就可以了,无需调用 Cast 。我怀疑Cast的源代码实现非常简单,虽然我认为它在3.5和3.5SP1之间变化。但是,它可能需要以正常的迭代器块方式设置新的状态机等。如果可能的话,最好避免它。

即使新方法是通用的,类型推断通常应该为您处理,因此您不需要明确指定 T

其他提示

为什么不直接声明列表:

List<IB> aList = new List<IB>();

是否有特别的东西需要你有一个具体类的列表?


因此,在这种情况下,我会将列表作为域的一部分。有一个像IIBCollection这样的接口(例如),公开你希望读者能够访问的方法。例如:

interface IIBCollection{
    IEnumerable<IB> IBs { get; }
}

// and in your implementation you can do

IEnumerable<IB> IBs { 
    get { 
        foreach(IB ib in innerList) yield return ib; 
}}

它在内部实现为CastIterator,它比转换每个项目的foreach稍慢。

Cast方法将遍历列表并转换每个项目。

如果您要使用该列表数千次,只需将转换结果存储为列表。

如果无法做到(即每次更改列表),请考虑使用 List&lt; IB&gt; 而不是 List&lt; A&gt;

这不是C#中的协方差吗?我没有看到你想要做什么,所以我不能评论为什么它会成千上万次。

仅仅对两种方法进行基准测试(Cast扩展方法和带有强制转换的for循环)是一件相当简单的事情。但鉴于Cast是Enumerable类的扩展方法并且通常与IEnumerables进行交易,我想这正是它的实现。如果你想要最快的速度,最好实现你自己的扩展方法,该方法专门用于List(通过索引获取每个元素),考虑到迭代器的开销,这应该稍快一些。但是,这两种方法都需要花费O(n)时间,因此差异不应该很大。尽管如此,这仍然值得进行基准测试......

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top