【问题标题】:C# inherit private class and non-access of public memberC#继承私有类和公共成员不可访问
【发布时间】:2012-07-20 20:48:36
【问题描述】:

为什么私有类的子类的用户不能访问私有类的公共成员数据?以下对我来说似乎非常违反直觉,因为它不会编译:

public class OuterClassBase {
    private class PrivateInnerClass {
        public void DoSomething () {}
    }

    protected class ProtectedInnerClass : PrivateInnerClass {}
}


public class OuterClassDerived : OuterClassBase {
    public OuterClassDerived () {
        ProtectedInnerClass o = new ProtectedInnerClass();
        o.DoSomething(); // inaccessible due to its pretection level
    }
}

使PrivateInnerClass public/protected 允许代码编译...

【问题讨论】:

  • 我假设 OuterClassDerived 应该是 OuterClassDerived : OuterClassBase?
  • 这只是 C# 中的基本范围规则。公共范围可在类外访问。私有范围可以在类内部访问。受保护的范围在类内部和派生类中可用。
  • 反直觉?怎么样,如果您可以在定义它的范围之外访问私有类,现在这将是违反直觉的。
  • 制作PrivateInnerClass protected 将允许它编译。
  • 注意:只有内部类可以声明为protected

标签: c# inheritance


【解决方案1】:

来自 C# 4 规范的第 3.5 节:

成员声明允许控制成员访问。成员的可访问性由成员声明的可访问性(第 3.5.1 节)与直接包含类型的可访问性(如果有)相结合。
...
如果发生访问的文本位置包含在成员的可访问域(第 3.5.2 节)中,则允许访问成员。

然后在第 3.5.2 节(可访问域)中:

在程序 P 中以类型 T 声明的嵌套成员 M 的可访问域定义如下(注意 M 本身可能是一个类型):

  • 如果声明的 M 的可访问性是公共的,则 M 的可访问域是 T 的可访问域。
  • ...
  • 如果声明的 M 的可访问性是私有的,则 M 的可访问域是 T 的程序文本。

这里就是这种情况。所以DoSomething的可访问域是第一个子弹的PrivateInnerClass的可访问域……但PrivateInnerClass的可访问域是最后一个子弹的OuterClassBase的程序文本。

因此OuterClassDerived内的调用不在DoSomething的可访问域内,所以不能调用。

我真的很惊讶你可以从PrivateInnerClass 中派生出ProtectedInnerClass...

编辑:事实证明你不能......即使完全删除了 OuterClassDerived 类,你也会收到这个错误:

Test.cs(10,21): error CS0060: Inconsistent accessibility: base class
        'OuterClassBase.PrivateInnerClass' is less accessible than class
        'OuterClassBase.ProtectedInnerClass'

这违反了规范的第 10.1.4.1 节:

类类型的直接基类必须至少与类类型本身一样可访问(第 3.5.2 节)。例如,公共类派生自私有或内部类是编译时错误。

在这里,您尝试从私有类派生受保护类 - 受保护类比私有类更易于访问,因此会出现错误。

【讨论】:

    【解决方案2】:

    PrivateInnerClass 是 OuterClassBase 私有的——除了 OuterClassBase 之外没有人可以使用它(这就是私有的意思)。

    子类化不会改变规则,它仍然是私有的 - 如果子类化将打破私有约束并允许 OuterBaseClass 之外的人访问 PrivateInnerClass 的成员,那么这是非法的并且不会编译。

    换句话说,如果某些东西被声明为私有而不是私有,那么任何允许您绕过私有声明的技巧都不应编译(反射除外)。

    【讨论】:

    • 但是子类化发生在可以访问 PrivateInnerClass 的类 X 内部。也就是说,X 拥有 PrivateInnerClass,那为什么会有问题呢?因此,我不明白为什么这会破坏私有约束。
    • @trinithis PrivateInnerClass.DoSomething 是 OuterBaseClass 私有的(因为 PrivateInnerClass 是私有的),任何允许您从 OuterBaseClass 外部访问 PrivateInnerClass.DoSomething 的代码都是非法的,因为不允许任何人,甚至 OuterBaseClass 都不允许撤消PrivateInnerClass 减速的约束
    【解决方案3】:

    受保护的类不能从私有类继承,原因与公共类不能从内部类继承的原因相同:一个类不能比它的基类更容易访问。

    但是你为什么要这样做呢?您可以阻止其他类直接从 PrivateInnerClass 继承,但前提是它们位于不同的程序集中。你也可以做这样的事情;该框架对内部/公共类做了很多工作:

    public class OuterClassBase
    {
        private class PrivateInnerClass : ProtectedInnerClass
        {
        }
    
        protected abstract class ProtectedInnerClass
        {
            public void DoSomething() { }
        }
    
        protected ProtectedInnerClass ProtectedInnerClassFactoryMethod()
        {
            return new PrivateInnerClass();
        }
    }
    
    public class OuterClassDerived : OuterClassBase
    {
        public OuterClassDerived()
        {
            ProtectedInnerClass o = ProtectedInnerClassFactoryMethod();
            o.DoSomething();
        }
    } 
    

    【讨论】:

      猜你喜欢
      • 2011-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-04
      • 2020-09-01
      相关资源
      最近更新 更多