Rum*_*iya 44 c# oop access-modifiers
在C#中,我们无法在从基类重写方法时更改访问修饰符.例如
Class Base
{
   **protected** string foo()
   {
       return "Base";
   }
}
Class Derived : Base
{
   **public** override string foo()
   {
       return "Derived";
   }
}
这在C#中无效,会产生编译时错误.
我想知道原因,为什么不允许这样做.是否存在任何技术问题,或者是否会导致访问限制方面不一致的问题?
InB*_*een 30
更改派生类型中方法的访问修饰符毫无意义,这就是为什么不允许它:
案例1:使用更严格的访问权限覆盖
由于以下情况,显然不允许这种情况:
class Base
{
    public virtual void A() {}
}
class Derived: Base
{
    protected override void A()
}
现在我们可以说:
List<Base> list;
list.Add(new Derived());
list[0].A() //Runtime access exception
情况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";
    }
}
使用该new关键字,您可以为您的Derived类创建一个具有相同名称和签名的新虚拟方法.请注意,允许声明一个new方法virtual,因此任何派生类Derived都将被允许覆盖它.
不允许有人做以下事情:
 Base newBaseObject = new Derived();
 newBaseObject.WhoAmI() //WhoAmI is not accessible.
但这个事实与能否覆盖WhoAmI()无关.无论如何,这种情况永远不会是因为Base没有声明public WhoAmI().
所以在理论C#中Derived.WhoAmI()可以覆盖Base.WhoAmI()这样做没有实际好处因为你永远无法从基类调用虚方法,所以该new选项已经满足你的要求.
我希望这更清楚.
好的,我在Annotated C#参考文献中找到了Eric Lippert的一个小注释:
重写的虚方法仍被认为是引入它的类的方法.在某些情况下,重载决策规则更喜欢更多派生类型的成员...覆盖方法不会"移动"该方法属于此层次结构的位置.
因此,这是一个有意的规则,以防止"脆弱的基类"问题,并提供更好的版本控制,即基类更改时更少的问题.
但请注意,它与安全性,类型安全性或对象状态无关.