为什么在C#中,子类需要实现父接口才能隐藏父类的某个方法?

4
我是一个有用的助手,可以为您翻译文本。
我在使用第三方库时遇到了这种行为,在其中我需要隐藏和更改其中的一个方法。
我的设置如下:
interface IBaseInterface
{
    string MethodToHide();
}

class BaseClass : IBaseInterface
{
    public string MethodToHide()
    {
        return "BaseClass";
    }
}

class ChildClass : BaseClass
{
    new public string MethodToHide()
    {
        return "ChildClass";
    }
}

为什么当我运行以下代码时会出现这种情况:
var i = (IBaseInterface) (new ChildClass());
Console.WriteLine(i.MethodToHide());

输出结果为

BaseClass

,但是当将ChildClass的签名更改为

class ChildClass : BaseClass, IBaseInterface

输出结果为

ChildClass

为什么我需要显式地指定接口,才能让ChildClass隐藏BaseClass方法?

3个回答

4
您需要更多地了解覆盖隐藏之间的区别:
链接:Override versus Hide
简而言之:
隐藏(使用new)根据变量类型运行方法。
覆盖覆盖该方法,并仅使用子类的方法。
编辑:
当您使用接口变量时:
var i = (IBaseInterface) (new ChildClass());

编译器将会寻找与接口所使用的方法最匹配的内容。
因为您声明了 BaseClass 来实现该接口,所以其方法将被选择。

如果 ChildClass 没有 明确地 实现该接口,则编译器无法将方法链接到该接口。从它的角度来看,BaseClass 只是碰巧具有相同名称的方法。

当您 明确地 声明 ChildClass 也实现该接口时,其方法将成为最佳选择。


是的,但我对行为很感兴趣,在这种情况下我无法覆盖该方法。在ChildClass的实例化中,它被转换为接口而不是基类。那么为什么编译器选择基类的方法? - Tobias Rundbom
因为编译器的最佳选择是显式声明方法属于接口的BaseClass。从编译器的角度来看,子类恰好具有相同名称的方法。 - Yochai Timmer
我已经在答案中添加了更多关于这个的内容。 - Yochai Timmer
但是,即使ChildClass没有明确指定IBaseInterface,i.GetType().GetInterfaces().Contains(typeof(IBaseInterface))仍然返回true。难道不应该在子类上不指定接口也能正常工作吗? - Tobias Rundbom
它确实实现了接口。但是子类声明的方法并没有与接口链接。它从基类继承了接口。接口的方法与父类的方法相关联,因为它明确声明实现了该接口。 - Yochai Timmer

2
您需要在BaseClass中将MethodToHide标记为virtual。然后,您的ChildClass可以重写它。有关更多详细信息,请参见http://msdn.microsoft.com/en-us/library/9fkccyh4(v=vs.80).aspx
我相信这是规范的相关部分:
10.6.3 虚方法,在虚方法调用中,调用发生的实例的运行时类型决定要调用的实际方法实现。在非虚拟方法调用中,实例的编译时类型是决定因素。
因此,当您将原始对象转换为IBaseInterface时,它确定类型为BaseClass,因为它实现了该接口并调用其方法。在第二个示例中,它会解析为ChildClass并调用其方法。

1
我认为OP明确地询问的是如何隐藏,而不是覆盖。 - Kirk Woll
我无法这么做,因为BaseClass是第三方闭源库的一部分。虽然我知道我可以这么做,但我问的是行为。 - Tobias Rundbom

1

因为主类实现了接口。子类只是定义了一个新方法,与接口无关。事实上,子类隐藏了该方法 - 这就是“new”所做的。


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