当派生类重新实现接口时如何调用基本接口实现?

3

因为某些原因,我正在测试C#和.NET虚拟机的极限。我遇到了一些令人困惑的行为。

请看下面的类和接口:

public interface ITest
{
    void Test();
    void Test2();
}
public abstract class Base : ITest
{
    void ITest.Test()
    {
        Console.WriteLine("base");
    }
    public void Test2()
    {
        Console.WriteLine("base2");
    }
    public void Test3()
    {
        Console.WriteLine("base3");
    }
}
public class Impl : Base, ITest
{
    void ITest.Test()
    {
        Console.WriteLine("impl");
    }
    void ITest.Test2()
    {
        Console.WriteLine("impl2");
    }
    public void Test3()
    {
        Console.WriteLine("impl3");
    }
}

然后像这样使用它们:

        var i = new Impl();
        var b = (Base)i;
        var itest1 = (ITest)i;
        var itest2 = (ITest)b;
        itest1.Test();
        itest2.Test();
        itest1.Test2();
        itest2.Test2();
        i.Test2();
        b.Test2();
        i.Test3(); //for reference, a standard non-virtual method outside of an interface
        b.Test3();

我期望输出的内容应该是这样的:
impl
base
impl2
base2
impl2
base2
impl3
base3

当然,事情不可能那么简单。因此,实际输出是这样的:
impl
impl
impl2
impl2
base2
base2
impl3
base3

除了这种疯狂奇怪的行为外,是否有可能访问Base.Test()实现呢?

1
据我所见,它正在按照预期运行。强制转换并不等同于转换。 - Tony Hopkinson
准确地说,强制转换并不等同于转换。此外,我建议稍微修改一下问题的名称:当派生类显式重新实现接口时,如何调用基接口的显式实现? - Fernando Espinosa
2个回答

2
也许你应该检查一下为什么你觉得结果很奇怪。对我来说,看起来你得到了你实现的确切结果。
无法获取 Base.Test,因为没有 Base.Test。你需要通过接口显式地访问它,然后它不再是 Base,而是 Impl,因为底层真正的对象不是类型为 Base 的对象。

但是,如果您在Base和Impl中都添加了Test3方法,但未添加到接口中,则会看到我期望的base3、impl3行为。 - Earlz
关键在于你在Impl中重新实现了接口。因此它将使用其本地实现,而不是从Base继承的实现。 - Nick Zimmerman
因为它不是通过基本变量访问的。而且它不属于基本类型。那么为什么要调用基类的代码呢? - nvoigt
1
请注意,当您不将其转换为ITest时,您会得到Base的实现,因为它会沿着继承链进行,取得继承版本。 - Nick Zimmerman
接口不会被继承,而是被实现,因此每当您创建一个新的实现时,它就成为当前实现。因此,如果您将其转换为该接口(在本例中为ITest),则可以获得最新的实现。 - Nick Zimmerman
显示剩余8条评论

0

Base 显式地实现了 ITest.Test()。这是一种实现,但它是一个"私有"的实现,只能通过 ITest 接口访问。

此外,Impl 正在重新实现 ITest.Test(),因此当您尝试使用 itest2.Test() 时,您将指向这个后来的重新实现

这里有两个关键点:

  1. 没有公共的 Base.Test()
  2. 通过在 Impl重新实现它,您杀死了访问 Base 上的 ITest.Test() 实现的所有可能性。

重新实现,重新实现,重新实现。

我可以建议稍微修改一下问题的名称:如何在派生类显式重新实现接口时调用基接口显式实现? 因为这就是你所问的...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接