列表铸造算法和性能注意事项
我有以下代码
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);
}
}
我最初尝试传递一个列表,但是 不起作用。 经过 SO 的大量帮助后,我发现传递 IEnumerable 是将对象传递为 .ofType(IB) 的唯一方法。
对我来说不幸的是,在我的代码中,以下行将被执行数千次:
aList.Cast<IB>();
我想知道是否有人知道它是如何通过算法实现的(在 IL 中)以及它的时间顺序是什么。
也就是说,它比仅强制转换每个项目的 foreach 循环更快,或者这正是它的作用?
编辑 主类需要维护实际对象的列表。 但读者只能通过界面触摸它们。
I have the following code
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);
}
}
I originally tried passing a List but that doesn't work.
After a lot of help from SO I found that passing IEnumerable is the only way to get the objects across as .ofType(IB).
Unfortunately for me, in my code the following line will be executed thousands of times:
aList.Cast<IB>();
I was wondering if anyone knew how it was implemented algorithmically (in IL) and what its time order is.
That is to say, is it faster than a foreach loop that just casts each item, or is that exactly what it does?
EDIT The main class needs to maintain a list of the actual objects. But the reader is only allowed to touch them through the interface.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您应该将
Go
更改为:那么您就不需要调用
Cast
了。 我怀疑 Cast 的源代码实现非常简单,尽管我相信它在 3.5 和 3.5SP1 之间发生了变化。 然而,它可能需要以正常的迭代器块方式设置一个新的状态机等。 如果可能的话最好避免它。尽管新方法是通用的,类型推断通常应该为您处理它,因此您不需要显式指定
T
。You should change
Go
to:Then you'll be fine with no need to call
Cast
. I suspect the source code implementation of Cast is pretty simple, although I believe it changed between 3.5 and 3.5SP1. However, it probably needs to set up a new state machine etc in the normal iterator block fashion. Better to avoid it if possible.Even though the new method is generic, type inference should usually take care of it for you so you don't need to specify
T
explicitly.为什么不直接声明该列表,例如:
是否有特殊的东西要求您拥有具体类的列表?
因此,在这种情况下,我会将列表作为域的一部分。 拥有像 IIBCollection 这样的接口(例如),公开您希望读者能够访问的方法。 例如:
Why not just declare the list like:
Is there something in particular that requires you to have a list of the concrete classes?
So in that case I'd make the list part of the domain. Have an interface like IIBCollection (for example), expose the methods on that you want the reader to be able to access. For example:
它在内部实现为 CastIterator,它比强制转换每个项目的 foreach 稍慢。
It's implemented internally as a CastIterator which is slightly slower than a foreach that casts each item.
Cast 方法将仅循环遍历列表并转换每个项目。
如果您要使用该列表数千次,只需将转换结果存储为列表即可。
如果这是不可能的(即每次更改列表),请考虑使用
List
而不是List
。The Cast method will just loop through the list and cast each item.
If you are going to use the list thousands of time, just store the result of the casting as a list.
If that is not possible (i.e. you change the list each time), consider working with a
List<IB>
instead of aList<A>
.这不是 C# 中协变的用途吗? 我不明白你想做什么,所以我无法评论为什么它被执行了成千上万次。
Isn't this what covariance in C# is for? I don't see what you're trying to do, so I can't comment on why it's exeuted thousands and thousands of times.
只需对两种方法(Cast 扩展方法和带强制转换的 for 循环)进行基准测试就相当简单了。 但考虑到 Cast 是 Enumerable 类的扩展方法,并且一般处理 IEnumerables,我想这正是它的实现。 如果您想要最大的速度,最好实现您自己的专门用于 List 的扩展方法(通过索引获取每个元素),考虑到迭代器的开销,该方法应该稍微快一些。 不过,这两种方法都需要 O(n) 时间,因此差异应该不会很大。 尽管如此,这是值得进行基准测试的东西......
It would be a fairly simple matter just to benchmark the two methods (Cast extension method and a for loop with a cast). But given that Cast is an extension method of the Enumerable class and deals generically with IEnumerables, I'd imagine this is precisely it's implementation. If you want the greatest speed, it may be best to implement your own extension method that works specifically on List (gets each element by its index), which should be slightly faster given the overhead of iterators. Still, both methods should take O(n) time, so the difference ought not be huge. It's something worth benchmarking, nonetheless...