可访问性不一致:基类比子类更难访问

fhn*_*eer 7 c# inheritance base-class

我正在读约瑟夫·阿尔巴巴里和本·阿尔巴巴里的书"简而言之的C#4.0".从那里我发现访问修饰符的主题限制.第91页,主题"访问修饰符的限制".

从书中引用.

编译器会阻止任何不一致的访问修饰符的使用.例如,子类本身可以比基类更难访问,但不能更多

所以这说明基类应该与子类相同或更易于访问.因此,如果基类是内部的,那么子类应该是私有的或内部的.如果基类是私有的,而子类是公共的,那么将生成编译时错误.在Visual Studio中尝试这个时,我发现了一些奇怪的行为.

尝试1:Base是私有的,子类是私有的(Works,正确的行为)如果两者都是内部的,那么它也有效.

private class A { }
private class B : A { }         // Works
Run Code Online (Sandbox Code Playgroud)

尝试2:Base是私有的,子类是public或internal(这是失败的,正确的行为)

private class A { }
public class B : A { }          // Error
Run Code Online (Sandbox Code Playgroud)

尝试3:Base是内部的,sub是公共的(这是有效的,但它应该失败.因为Base比子类更难访问

internal class A { }
public class B : A { }          // Works, but why
Run Code Online (Sandbox Code Playgroud)

现在我的问题是为什么试试3没有失败?子类是公共的,比内部的基类更容易访问.即使这本书说这应该失败.但Visual Studio成功编译了这个.这应该工作与否?

编辑:

我在VS中创建了一个新的控制台项目.在Program.cs中,我添加了我的代码.这是Program.cs文件的完整代码.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication
{
    class Program
    {
        internal class A { }
        public class B : A { }          // Error

        static void Main()
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Chr*_*air 11

您将嵌套类放在另一个internal类中.

例如,给定:

class Program
{
    static void Main(string[] args)
    {
    }

    internal class A { }
    public class B : A { }
}
Run Code Online (Sandbox Code Playgroud)

编译,因为internal包装类的修饰使得public阶级修改B实际意义.相反,类型B的可访问性受其包装类的限制Program- 它的可访问性域也是internal如此.

如果您将其更新为:

class Program
{
    static void Main(string[] args)
    {
    }
}

internal class A { }
public class B : A { }
Run Code Online (Sandbox Code Playgroud)

它将抛出不一致的可见性编译器错误.或者,如果你重新定义Programpublic不是internal也会抛出错误.在这种情况下,B的访问域现在public,不再受限制Programs'的internal访问域.


来自C#规范3.5.2可访问域:

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

如果声明的M的可访问性是公共的,则M的可访问域是T的可访问域.

以及MSDN对辅助功能域的描述:

如果成员嵌套在另一个类型中,则其可访问性域由成员的可访问性级别和直接包含类型的可访问性域确定.

如果包装类型Programinternal,那么嵌套类型B的存在public都会有它的辅助功能相匹配Program,因此它被视为internal没有编译器错误被抛出.