为什么我们不能在覆盖C#中的方法时更改访问修饰符?

Rum*_*iya 44 c# oop access-modifiers

在C#中,我们无法在从基类重写方法时更改访问修饰符.例如

Class Base
{
   **protected** string foo()
   {
       return "Base";
   }
}

Class Derived : Base
{
   **public** override string foo()
   {
       return "Derived";
   }
}
Run Code Online (Sandbox Code Playgroud)

这在C#中无效,会产生编译时错误.

我想知道原因,为什么不允许这样做.是否存在任何技术问题,或者是否会导致访问限制方面不一致的问题?

InB*_*een 30

更改派生类型中方法的访问修饰符毫无意义,这就是为什么不允许它:

案例1:使用更严格的访问权限覆盖

由于以下情况,显然不允许这种情况:

class Base
{
    public virtual void A() {}
}

class Derived: Base
{
    protected override void A()
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以说:

List<Base> list;
list.Add(new Derived());
list[0].A() //Runtime access exception
Run Code Online (Sandbox Code Playgroud)

情况2:使用限制较少的访问修饰符覆盖

有什么意义?隐藏方法,你就完成了.显然,如果有人通过基类型调用,则他们将无法访问派生类型中定义的新方法,但这与基类型的作者想要的内容一致,因此您没有"权利"来更改它.如果你想从派生类调用派生类调用的细节,在这种情况下该new方法完全正常.

编辑:扩展案例2

我想在案例2中说的是,如果你想改变可访问性,你已经有办法改变任何方法的可访问性(虚拟或非虚拟).

请考虑以下代码:

public class Base
{
    protected virtual string WhoAmI()
    {
        return "Base";
    }
}

public class Derived : Base
{
    public new virtual string WhoAmI()
    {
        return "Derived";
    }
}

public class AnotherDerived : Derived
{
    public override string WhoAmI()
    {
        return "AnotherDerived";
    }
}
Run Code Online (Sandbox Code Playgroud)

使用该new关键字,您可以为您的Derived类创建一个具有相同名称和签名的新虚拟方法.请注意,允许声明一个new方法virtual,因此任何派生类Derived都将被允许覆盖它.

不允许有人做以下事情:

 Base newBaseObject = new Derived();
 newBaseObject.WhoAmI() //WhoAmI is not accessible.
Run Code Online (Sandbox Code Playgroud)

但这个事实与能否覆盖WhoAmI()无关.无论如何,这种情况永远不会是因为Base没有声明public WhoAmI().

所以在理论C#中Derived.WhoAmI()可以覆盖Base.WhoAmI()这样做没有实际好处因为你永远无法从基类调用虚方法,所以该new选项已经满足你的要求.

我希望这更清楚.

  • 我不明白你怎么说“这样做没有实际好处,因为无论如何你永远无法从基类调用虚方法”。基类定义“受保护的虚拟”方法以使子类能够更改基类中的实现所表现出的行为是很常见的。关于案例 2 的问题是如何 1. 覆盖 `protected vritual MemberName` 和 2. 公开一个名为 `MemberName` 的公共成员。听起来如果不将单个子类替换为两个子类以递增地“覆盖”然后“新”是不可能的。 (2认同)

Hen*_*man 9

好的,我在Annotated C#参考文献中找到了Eric Lippert的一个小注释:

重写的虚方法仍被认为是引入它的类的方法.在某些情况下,重载决策规则更喜欢更多派生类型的成员...覆盖方法不会"移动"该方法属于此层次结构的位置.

因此,这是一个有意的规则,以防止"脆弱的基类"问题,并提供更好的版本控制,即基类更改时更少的问题.

但请注意,它与安全性,类型安全性或对象状态无关.