我有以下代码
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);
}
}
我最初尝试传递一个列表但doesn't work。 经过SO的大量帮助后,我发现传递IEnumerable是获取对象的唯一方法.ofType(IB)。
不幸的是,在我的代码中,以下行将被执行数千次:
aList.Cast<IB>();
我想知道是否有人知道它是如何通过算法实现的(在IL中)以及它的时间顺序是什么。
也就是说,它是否比仅仅投射每个项目的foreach循环更快,还是正是它所做的那样?
编辑主类需要维护实际对象的列表。但是只允许读者通过界面触摸它们。
答案 0 :(得分:10)
您应该将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
。
答案 1 :(得分:5)
为什么不直接声明列表:
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;
}}
答案 2 :(得分:1)
它在内部实现为CastIterator,它比转换每个项目的foreach稍慢。
答案 3 :(得分:0)
Cast方法将遍历列表并转换每个项目。
如果您要使用该列表数千次,只需将转换结果存储为列表。
如果无法做到(即您每次都更改列表),请考虑使用List<IB>
代替List<A>
。
答案 4 :(得分:0)
这不是C#中的协方差吗?我没有看到你想要做什么,所以我不能评论为什么它会成千上万次。
答案 5 :(得分:0)
仅仅对两种方法进行基准测试(Cast扩展方法和带有强制转换的for循环)是一件相当简单的事情。但鉴于Cast是Enumerable类的扩展方法并且通常与IEnumerables进行交易,我想这正是它的实现。如果你想要最快的速度,最好实现你自己的扩展方法,该方法专门用于List(通过索引获取每个元素),考虑到迭代器的开销,这应该稍快一些。但是,这两种方法都需要花费O(n)时间,因此差异不应该很大。尽管如此,这仍然值得进行基准测试......