我应该投射我的lambda还是施放IEnumerable?

时间:2013-03-01 17:17:29

标签: c# linq casting

在我的项目中,我有一个MyClass来实现IMyClass。我需要通过转换其他项目列表来返回IMyClass列表。为简单起见,假设我只需将另一个项目传递给其构造函数即MyClass即可创建new MyClass(item)

考虑以下两行,(据我所知)产生相同的结果:

var option1 = items.Select(item => new MyClass(item)).Cast<IMyClass>().ToList()
var option2 = items.Select(item => new MyClass(item) as IMyClass).ToList()

在我看来,选项#1需要双枚举,一次将所有项目转换为我的界面,一次生成列表。如果我是对的那么选项#2会更聪明。但是,我永远不会看到使用类似#2选项的任何代码,我倾向于认为我不够聪明,想出一些聪明的东西,其余的C#社区没有

另一方面,我认为选项#2更美观,但那只是我。

我的问题是:是我的选择#2更好的主意,就像我认为的那样?是否有任何我想念的陷阱或其他原因我为什么要坚持选项#1?或者我可能比较两个愚蠢的想法,当有一个更聪明的第三个我完全缺失的时候?

4 个答案:

答案 0 :(得分:18)

我会选择选项3:

var option3 = items.Select<Foo, IMyClass>(item => new MyClass(item))
                   .ToList()

或者,不要使用as,而只是正常施放:

var option4 = items.Select(item => (IMyClass) new MyClass(item))
                   .ToList()

这两个看起来都比使用Cast更清晰。

哦,从.NET 4的C#4开始(由于协方差),你可以在ToList调用上设置一个类型参数:

var option5 = items.Select(item => new MyClass(item))
                   .ToList<IMyClass>()

答案 1 :(得分:3)

  

在我看来,选项#1需要双重枚举

事实并非如此。在这两种情况下,items集合仅在您到达ToList()时进行枚举。

该行

var option1 = items.Select(item => new MyClass(item)).Cast<IMyClass>().ToList()

相当于

var option1 = items.Select(item => new MyClass(item)).Select(x => (IMyClass)x).ToList()

两者之间的唯一区别是第一个需要每个项目有两个函数调用(除非C#以某种方式内联lambda,我认为不是这种情况),而第二个选项只需要一个。

就个人而言,我会选择第二个作为风格问题。

答案 2 :(得分:1)

您使用哪一个是偏好问题,我们真的无法为您解答。

但你的直觉如果排序正确Cast为你的循环增加了第二层迭代。它非常小,我怀疑它会在性能上产生任何可测量的差异,但Cast方法返回一个新的IEnumerable对象,基本上这样做:

foreach (object obj in source) yield return (TResult)obj;

效果主要是调用堆栈的另一个级别;因为它使用yield,它只会按需迭代,就像大多数其他IEnumerable方法一样。但它必须返回两个级别的迭代器状态而不是一个。这对您来说是否重要,您需要根据自己的应用进行衡量。

(另请注意,至少根据参考源,它会进行不安全的转换,如果转换无效,可能会抛出异常。这是另一个选择#2选项的原因。 )

答案 3 :(得分:1)

您始终可以为Select

提供显式类型参数
   var option2 = items.Select<IItem,IMyClass>(item => new MyClass(item)).ToList();

其中IItem是可以投射项目的类型或接口。