gpt4 book ai didi

c# - 为什么对泛型的显式接口(interface)调用总是调用基础实现?

转载 作者:可可西里 更新时间:2023-11-01 07:58:00 24 4
gpt4 key购买 nike

为什么在具有接口(interface)类型约束的泛型方法中显式 C# 接口(interface)调用总是调用基实现?

例如,考虑以下代码:

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();
}
}

此代码输出以下内容:

IDerived.Method
IBase.Method

而不是人们可能期望的:

IDerived.Method
IDerived.Method

似乎没有办法(缺少反射)调用运行时决定的类型的隐藏的、更派生的显式接口(interface)实现。

编辑:为了清楚起见,以下 if 检查在上面的 GenericMethod 调用中评估为真:

if (typeof(T) == typeof(IDerived))

所以答案并不是由于泛型类型约束“where T : class, IBase”,T 总是被视为 IBase。

最佳答案

这里的关键是要记住IBase.MethodIDerived.Method 是两种完全不同的方法。我们只是碰巧给了他们相似的名字和签名。由于任何实现了 IDerived 的东西也实现了 IBase,这意味着它将有两个名为 Method 的方法,不带参数。一个属于IDerived,一个属于IBase

编译器在编译GenericMethod时只知道泛型参数至少会实现IBase,所以它只能保证IBase.Method 实现存在。这就是调用的方法。

与 C++ 模板不同,泛型替换不会在方法编译时发生(对于模板,对于所使用的模板参数的每个组合都会发生一次)。相反,该方法只编译一次,这样任何类型都可以在运行时被替换。

在您的情况下,编译器为 GenericMethod 发出如下所示的 IL:

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

请注意它显式调用了 IBase.Method。该方法与 IDerived.Method 之间没有虚拟/覆盖关系,因此调用的都是基类,无论在运行时用什么类型替代 T。

关于c# - 为什么对泛型的显式接口(interface)调用总是调用基础实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38535691/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com