HLo*_*nzi 9 c# overload-resolution
假设我在C#中有这个:
class OverloadTest
{
void Main()
{
CallWithDelegate(SomeOverloadedMethod);
}
delegate void SomeDelegateWithoutParameters();
delegate void SomeDelegateWithParameter(int n);
void CallWithDelegate(SomeDelegateWithoutParameters del) { }
void CallWithDelegate(SomeDelegateWithParameter del) { }
void SomeOverloadedMethod() { }
void SomeOverloadedMethod(int n) { }
}
Run Code Online (Sandbox Code Playgroud)
当然,这不会编译,因为该行CallWithDelegate(SomeOverloadedMethod);是模糊的.
现在,假设只有一个CallWithDelegate(SomeDelegateWithoutParameter del)函数(没有重载).在这种情况下,没有歧义,因为从似乎正在发生的事情,编译器可以查看参数类型并SomeOverloadedMethod(int n)从候选列表中丢弃(因为它只能占用a SomeDelegateWithoutParameters),因此它编译.
我不打算写这样的代码; 从编译器编写者的角度来看,这只是出于好奇.我找不到关于这个问题的答案,因为用语言表达是很困惑的.
我想知道C#中是否有任何方法可以消除Main()给定示例中的调用,以便编译.如何指定它以便它被解析为CallWithDelegate(SomeDelegateWithoutParameters del)传递SomeOverloadedMethod()或被CallWithDelegate(SomeDelegateWithParameter del)传递SomeOverloadedMethod(int n)?
Luc*_*ski 10
有几种方法可以消除方法组的重载决策.
CallWithDelegate((SomeDelegateWithoutParameters)SomeOverloadedMethod);
CallWithDelegate((SomeDelegateWithParameter)SomeOverloadedMethod);
Run Code Online (Sandbox Code Playgroud)
这消除了过载的歧义.这是非常罕见的语法,但它有效(C#5规范§6.6方法组转换):
与所有其他隐式和显式转换一样,转换运算符可用于显式执行方法组转换.
[...]
方法组可能会影响重载决策,并参与类型推断.
CallWithDelegate(new SomeDelegateWithoutParameters(SomeOverloadedMethod));
CallWithDelegate(new SomeDelegateWithParameter(SomeOverloadedMethod));
Run Code Online (Sandbox Code Playgroud)
这与没有语法糖的前一种方法相同.有关更多详细信息,请参阅§7.6.10.5委托创建表达式中的规范.
表单的委托创建表达式的绑定时处理
new D(E),其中D是委托类型并且E是表达式,包括以下步骤:
- 如果
E是方法组,则委托创建表达式以相同的方式处理为从方法组转换(6.6节)E来D.[...]
甚至有一个与你的问题密切相关的例子:
如上所述,当从方法组创建委托时,委托的形式参数列表和返回类型确定要选择哪个重载方法.在示例中
Run Code Online (Sandbox Code Playgroud)delegate double DoubleFunc(double x); class A { DoubleFunc f = new DoubleFunc(Square); static float Square(float x) { return x * x; } static double Square(double x) { return x * x; } }该
A.f字段使用引用第二种Square方法的委托进行初始化,因为该方法与形式参数列表和返回类型完全匹配DoubleFunc.如果第二种Square方法不存在,则会发生编译时错误.
CallWithDelegate(() => SomeOverloadedMethod());
CallWithDelegate(i => SomeOverloadedMethod(i));
CallWithDelegate((int i) => SomeOverloadedMethod(i)); // Explicit types, if needed
Run Code Online (Sandbox Code Playgroud)
这个表单不含糊,但它有一个间接(lambda被调用,然后它调用目标方法).这可能会被JIT优化,但它最有可能不会产生明显的性能影响.
CallWithDelegate(delegate() { SomeOverloadedMethod(); });
CallWithDelegate(delegate(int i) { SomeOverloadedMethod(i); });
Run Code Online (Sandbox Code Playgroud)
这相当于lambda调用,但它使用了较大(和较旧)的delegate语法.
如果您想知道确切的重载决策规则,则在§7.5.3过载分辨率的规范中对它们进行了描述.