【发布时间】:2018-02-13 13:51:26
【问题描述】:
考虑这段代码 sn-p,具有泛型和重载函数:
using System;
namespace Test_Project
{
public interface Interface
{
void f();
}
public class U : Interface
{
public void f() {}
}
public class Class<T> where T: Interface
{
public static void OverloadedFunction(T a)
{
Console.WriteLine("T");
a.f();
}
public static void OverloadedFunction(U a)
{
Console.WriteLine("U");
a.f();
}
}
class Program
{
public static void Invoke(U instance)
{
Class<U>.OverloadedFunction(instance);
}
static void Main(string[] args)
{
Invoke(new U());
}
}
}
我会说它无法编译,因为我有两个适合 OverloadedFunction 的候选方法。但是它会打印“U”。
在生成的IL中,我可以看到:
.method public hidebysig static
void Invoke (
class Test_Project.U 'instance'
) cil managed
{
// Method begins at RVA 0x2085
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call void class Test_Project.Class`1<class Test_Project.U>::OverloadedFunction(class Test_Project.U)
IL_0006: ret
} // end of method Program::Invoke
意味着 C# 编译器将对 OverloadedFunction 的调用解析为调用,而不是“通用”函数所需的 callvirt。 从编译器的角度来看,我可以猜测 'U' 方法是一个更好的候选者,但我无法明确解释为什么......
我真的很想了解这里发生了什么,但我不知道。
但是,如果您考虑到 sn-p 的这个修改版本,它会变得更加奇怪,我们在其中引入了另一个级别的间接:
using System;
namespace Test_Project
{
public interface Interface
{
void f();
}
public class U : Interface
{
public void f() {}
}
public class V : U { }
public class Class<T> where T: Interface
{
public static void OverloadedFunction(T a)
{
Console.WriteLine("T");
a.f();
}
public static void OverloadedFunction(U a)
{
Console.WriteLine("U");
a.f();
}
}
class Program
{
public static void Invoke(V instance)
{
Class<V>.OverloadedFunction(instance);
}
static void Main(string[] args)
{
Invoke(new V());
}
}
}
我希望这个程序仍然打印“U”,因为“V”是继承的“U”。但它会打印“T”,如 MSIL 所示:
.method public hidebysig static
void Invoke (
class Test_Project.V 'instance'
) cil managed
{
// Method begins at RVA 0x208d
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call void class Test_Project.Class`1<class Test_Project.V>::OverloadedFunction(!0)
IL_0006: ret
} // end of method Program::Invoke
表示通用版本已被 c# 编译器首选。
在泛型参数和继承方面,请有人解释重载方法解析的规则是什么?
【问题讨论】:
-
显然,一旦你结合了继承和覆盖,编译器的函数解析变得奇怪:stackoverflow.com/a/48735728/3346583我假设接口的解析类似于继承(它毕竟是不允许多重继承的修复) .
标签: c# generics inheritance overloading