在我的项目中,我有一个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?或者我可能比较两个愚蠢的想法,当有一个更聪明的第三个我完全缺失的时候?
答案 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是可以投射项目的类型或接口。