我研究使用Visual Studio在C#/ .NET中开发的应用程序.在我的方法的原型中,ReSharper经常建议我用更通用的输入参数替换输入参数的类型.例如,List<>使用IEnumerable<>如果我只在我的方法体中使用带有foreach的列表.我可以理解为什么写这个看起来更聪明,但我非常关心性能.我担心如果我听ReSharper我的应用程序的性能会降低…
当我写作时,有人可以准确地(或多或少地)向我解释幕后发生的事情(即在CLR中):
public void myMethod(IEnumerable<string> list) { foreach (string s in list) { Console.WriteLine(s); } } static void Main() { List<string> list = new List<string>(new string[] {"a","b","c"}); myMethod(list); }
和有什么区别:
public void myMethod(List<string> list) { foreach (string s in list) { Console.WriteLine(s); } } static void Main() { List<string> list = new List<string>(new string[] {"a","c"}); myMethod(list); }
解决方法
你担心表现 – 但你有任何理由担心这个问题吗?我的猜测是你根本没有对代码进行基准测试.在使用性能更高的代码替换可读,干净的代码之前始终进行基准测试
在这种情况下,对Console.WriteLine的调用无论如何都将完全支配性能.
虽然我怀疑使用List< T>之间的性能可能存在理论上的差异.和IEnumerable< T>在这里,我怀疑在现实世界的应用程序中它具有重要意义的案例数量正在逐渐减少.
它甚至不是用于许多操作的序列类型 – 只有一次调用GetEnumerator(),它被声明为返回IEnumerator< T>.无论如何.随着列表变大,两者之间的性能差异将变得更小,因为它只会在循环开始时产生任何影响.
但是,忽略分析,要做的就是在对其进行编码决策之前测量性能.
至于幕后发生的事情 – 你必须深入研究每种情况下元数据中究竟是什么的深层细节.我怀疑在接口的情况下,有一个额外的重定向级别,至少在理论上 – CLR必须解决目标对象类型中IEnumerable< T>的vtable的位置.是,然后调用适当的方法的代码.在List< T>的情况下,JIT将知道开始的vtable中的正确偏移,而没有额外的查找.这只是基于我对JITting,thunking,vtables以及它们如何应用于接口的朦胧理解.它可能略有错误,但更重要的是它是一个实现细节.