泛型与非泛型重载调用
Posted
技术标签:
【中文标题】泛型与非泛型重载调用【英文标题】:Generic vs Non-Generic Overload Calling 【发布时间】:2012-04-12 21:53:58 【问题描述】:当我声明这样的方法时:
void DoWork<T>(T a)
void DoWork(int a)
然后用这个来调用它:
int a = 1;
DoWork(a);
它将调用什么DoWork
方法,为什么?我似乎在任何 MSDN 文档中都找不到它。
【问题讨论】:
很容易发现它会调用第二个(Visual Studio 显示大约 1 分钟),但至于为什么,我可以猜到,但对编译器有更多了解的人应该能够给你一个体面的答案。 【参考方案1】:作为 Eric Lippert says:
The C# specification says that when you have a choice between calling
ReallyDoIt<string>(string)
andReallyDoIt(string)
– that is, when the choice is between two methods that have identical signatures, but one gets that signature via generic substitution – then we pick “自然”签名优于“替代”签名。
更新:
我们在 C# 规范 (7.5.3) 中的内容:
当在没有指定类型参数的情况下调用泛型方法时,类型推断过程会尝试推断调用的类型参数。通过类型推断,类型参数 int 由方法的参数确定。类型推断作为方法调用的绑定时处理的一部分发生,并在调用的重载解决步骤before
发生。
如果在方法调用中指定了特定方法组,并且没有将类型参数指定为方法调用的一部分,则类型推断将应用于方法组中的每个泛型方法。如果类型推断成功,则推断的类型参数用于确定后续重载决议的参数类型。如果重载决议选择一个泛型方法作为调用的方法,那么推断的类型参数将用作调用的实际类型参数。如果特定方法的类型推断失败,则该方法不参与重载决策。
所以在重载决议之前,我们在方法组中有两个方法。一个DoWork(int)
和另一个推断DoWork<int>(int)
。
然后我们转到 7.5.3.2(更好的函数成员):
如果参数类型序列 P1, P2, ..., PN 和 Q1, Q2, ..., QN 等价(即每个 Pi 有一个到相应 Qi 的恒等转换),以下平局规则应用,以便确定更好的功能成员。 1) 如果 MP 是非泛型方法,MQ 是泛型方法,则 MP 优于 MQ。
【讨论】:
在行然后我们选择“自然”签名而不是“替代”签名,我们做什么意思是,它是编译器吗?为什么 natural 签名更适合这种情况?是因为性能吗? @JohnIsaiahCarmona - 这里有一些性能优势,是的,以及开发人员的一些灵活性优势。做出此选择的主要原因是规格说明如此。 平局规则在C# language spec的“7.4.3.2更好的函数成员”部分中指定:如果MP是非泛型方法,MQ是泛型方法,则MP比MQ好。 这背后的逻辑是:如果你知道如何用非泛型方法处理这种特定类型,非泛型方法获胜;否则,回退到泛型方法。 查看我关于更好的功能成员选择的评论。 不是为了性能,而是为了特异性。如果你有一个方法说“我可以 frob 长颈鹿列表”,并且你有一个方法说“我可以为你命名的任何类型 T 提供 T”,然后你说“嘿,我想 frob这个长颈鹿列表”,编译器选择专门为此而设计的方法似乎是合理的。换句话说:假设我们选择了泛型方法。 您可以编写哪些代码来选择非泛型代码?以上是关于泛型与非泛型重载调用的主要内容,如果未能解决你的问题,请参考以下文章