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