Fan*_*ade 14 .net c# generics explicit-interface
为什么在具有接口类型约束的泛型方法中的显式C#接口调用总是调用基本实现?
例如,请考虑以下代码:
public interface IBase
{
string Method();
}
public interface IDerived : IBase
{
new string Method();
}
public class Foo : IDerived
{
string IBase.Method()
{
return "IBase.Method";
}
string IDerived.Method()
{
return "IDerived.Method";
}
}
static class Program
{
static void Main()
{
IDerived foo = new Foo();
Console.WriteLine(foo.Method());
Console.WriteLine(GenericMethod<IDerived>(foo));
}
private static string GenericMethod<T>(object foo) where T : class, IBase
{
return (foo as T).Method();
}
}
Run Code Online (Sandbox Code Playgroud)
此代码输出以下内容:
IDerived.Method
IBase.Method
而不是人们可能期望的:
IDerived.Method
IDerived.Method
似乎没有办法(缺少反射)来调用在运行时决定的类型的隐藏的,更加派生的显式接口实现.
编辑:要清楚,如果检查在上面的GenericMethod调用中计算结果为true:
if(typeof(T)== typeof(IDerived))
所以答案并不是因为泛型类型约束"T:class,IBase",T总是被视为IBase.
这里的关键是要记住,IBase.Method并且IDerived.Method是两个完全不同的方法.我们碰巧给了他们相似的名字和签名.因为实现的任何东西IDerived也实现了IBase,这意味着它将有两个名为Method不带参数的方法.一个属于IDerived一个属于一个属于IBase.
所有编译器都知道编译时GenericMethod通用参数至少会实现IBase,所以它只能保证IBase.Method实现存在.这就是所谓的方法.
与C++模板不同,无论何时编译方法都不会发生泛型替换(对于使用的每个模板参数组合,模板都会发生一次).相反,该方法只需编译一次,以便在运行时可以替换任何类型.
在你的情况下,编译器发出IL GenericMethod,看起来像这样:
IL_0000: ldarg.0
IL_0001: isinst <T>
IL_0006: unbox.any <T>
IL_000B: box <T>
IL_0010: callvirt IBase.Method
IL_0015: ret
Run Code Online (Sandbox Code Playgroud)
注意它显式调用IBase.Method.还有该方法之间不存在虚拟/倍率关系IDerived.Method这样的碱是所有这就是所谓,不管是什么类型被在运行时被取代的对于T.