C# 定义采用IEnumerable类型约束或基类的方法?

C# 定义采用IEnumerable类型约束或基类的方法?,c#,generics,C#,Generics,我早些时候问了一个关于这个问题的问题。有人很快指出,不能将列表传递给需要列表的方法 进一步的探索(以及一些有用的链接,如)表明,虽然不能将List传递到List,但可以将List传递到IEnumerable(由于.NET 4中的逆变/协方差) 就像在我前面的问题中一样,我在这里提出了同样的一个问题:既然使用这两个选项似乎没有区别,那么哪一个更好?这是一个严格的基于风格的东西,还是使用其中一个对另一个有影响 选项A:void DoWork(IEnumerable objs),其中TBase:Bas

我早些时候问了一个关于这个问题的问题。有人很快指出,不能将
列表
传递给需要
列表
的方法

进一步的探索(以及一些有用的链接,如)表明,虽然不能将
List
传递到
List
,但可以将
List
传递到
IEnumerable
(由于.NET 4中的逆变/协方差)

就像在我前面的问题中一样,我在这里提出了同样的一个问题:既然使用这两个选项似乎没有区别,那么哪一个更好?这是一个严格的基于风格的东西,还是使用其中一个对另一个有影响

选项A:
void DoWork(IEnumerable objs),其中TBase:Base

选项B:
void DoWork(IEnumerable objs)

选项A

void DoWork<TBase>(IEnumerable<TBase> objs) where TBase : Base;
IEnumerable
可以包含
Base
或从中继承的任何内容

在这两种情况下,除非有一些丑陋的类型检查,否则根据
Base
的定义,每个方法只能与
IEnumerable
中的元素交互,因为它“知道”的只是这些元素


如果方法返回
Base
TBase
,则差异将更有意义。然后调用者将能够传入
TBase
,并得到一个转换为
TBase
的结果。如果类型对调用方的重要性大于它对该方法的重要性,那么它不希望传入一个从
TBase
继承的参数,并将其结果转换为
Base

选项A的JIT稍大一些,因为
DoWork(new-TDerived[0])
DoWork(new-TBase[0])
是不同的方法调用。jitter的输出中会有很多共享代码(因为
TBase
TDerived
必须是引用类型才能真正不同,并且一个派生自另一个),但这有点多余

理论上,如果
DoWork
调用了一个虚拟方法,并且
t派生的
被密封,那么抖动就有可能利用这一点带来的好处,但我很确定,由于代码共享,这种情况不会发生。如果真的发生了,差别将很小

因此,在所有的情况下,选项B在不jitting更多版本的通用方法中获胜,选项A没有补偿优势

然而,如果选项A是:

TBase DoWorkAndReturnSomething(IEnumerable<TBase> objs) where TBase : Base
TBase-DoWorkAndReturnSomething(IEnumerable-objs),其中TBase:Base
这样你就不必投下结果。如果你真的在投结果,这才是真正的优势。如果您继续将其用作
Base
或将结果传递给采用
Base
的方法,那么您将无法补偿额外的抖动和额外的概念复杂性


因此,每种方法都有利弊。对于更广泛的情况,非泛型可能更好,但有时带有约束的泛型形式确实有优势。

选项a将允许在方法中编写类似于
new TBase()
。。。这只是一个立即浮现在脑海中的优势。@HimBromBeere您也可以使用
Base
作为
TBase
向第一个集合添加不同的类型。事实上,与使用
List
不同,使用
IEnumerable
将允许您向此方法发送实现
IEnumerable
的任何实例,其中
X
是派生的(或实现的)
T
。因此,关于什么更好的问题——好吧,在这种情况下,我认为这两种实现之间没有太大区别。泛型的可能会生成更多的编译代码,但我认为这并不重要。@Virustinity不,它不会-试试看。您将得到一个错误:
无法创建变量类型“TBase”的实例,因为它没有new()约束
。如果将声明更改为
where-TBase:Base,new()
,则可以使用
new
——但当然,您只能将其用于具有默认构造函数的类型。@MatthewWatson这是正确的,只是忘了提及它。
TBase DoWorkAndReturnSomething(IEnumerable<TBase> objs) where TBase : Base