【问题标题】:Inconsistent accessibility: base class is less accessible than child class可访问性不一致:基类比子类更难访问
【发布时间】:2013-05-15 00:46:31
【问题描述】:

我正在阅读 Joseph Albabari 和 Ben Albabari 所著的“C# 4.0 in a nutshell”一书。从那里我找到了关于访问修饰符的主题限制。第 91 页,主题“访问修饰符的限制”。

引用书中的内容。

编译器会防止任何不一致的访问修饰符使用。为了 例如,子类本身可能比基类更难访问, 但仅此而已

这就是说基类应该比子类具有同等或更多的可访问性。因此,如果基类是内部的,那么子类应该是私有的或内部的。如果基类是私有的,而子类是公共的,则会产生编译时错误。在 Visual Studio 中尝试此操作时,我发现了一些奇怪的行为。

尝试 1:基类是私有的,子类是私有的(有效,正确的行为)如果两者都是内部的,公共的,这也有效。

private class A { }
private class B : A { }         // Works

尝试 2:基类是私有的,子类是公共的或内部的(这失败了,正确的行为)

private class A { }
public class B : A { }          // Error

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

internal class A { }
public class B : A { }          // Works, but why

现在我的问题是为什么 Try 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()
        {
        }
    }
}

【问题讨论】:

  • 从技术上讲,internal 可以通过InternalsVisibleTo attribute 在程序集外部使用,所以这可能就是它背后的原因。我会看看能否在 C# 规范中找到特定的条目。
  • 为我尝试 3 个作品,即。无法编译,出现不一致的可访问性错误。
  • 我也想到了 InternalsVisibleTo 属性,但是如果我在我的程序集文件中没有提到这个怎么办。这肯定有其他原因。
  • 附带说明,这个问题可以作为教科书示例,说明为什么 Jon Skeet 总是强调您应该在问题中包含一个“简短但完整”程序。一旦问题被编辑,问题就很明显了。在此之前,一个谜:-)
  • 这里有一个谜题,看看你是否理解规则。 public class Alpha { protected internal class Bravo {} } 在程序集 Alpha.DLL 中,public class Charlie : Alpha { xxx class Delta : Bravo {} } 在程序集 Charlie.DLL 中。可访问性修饰符xxx 的合法值是什么?

标签: c# inheritance base-class


【解决方案1】:

当你用其他公共类继承私有类时,私有继承类不能在其他类中访问,那么它包含私有类的引用及其数据,所以这是不可能的。

abstract class test
    {
        public abstract void add();
        public int num1;
        public string str;
    }
class test3 : test1
    {
        public override void add()
        {
            throw new NotImplementedException();
        }
    }

这两个类都是私有的。 如果您使用 internal 那么您只能在程序集中访问。

【讨论】:

    【解决方案2】:

    您将嵌套类置于另一个internal 类中。

    例如,给定:

    class Program
    {
        static void Main(string[] args)
        {
        }
    
        internal class A { }
        public class B : A { }
    }
    

    编译,因为包装类的internal 修饰符使得B 类上的public 修饰符没有实际意义。相反,类型B 的可访问性受到其包装类Program 的限制——它的可访问域也是internal

    如果您将其更新为:

    class Program
    {
        static void Main(string[] args)
        {
        }
    }
    
    internal class A { }
    public class B : A { }
    

    它会抛出不一致的可见性编译器错误。或者,如果您将Program 重新定义为public 而不是internal,它也会抛出错误。在这种情况下,B 的可访问域现在是 public 并且不再受 Programinternal 可访问域的限制。


    来自 C# 规范3.5.2 Accessibility Domains

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

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

    还有无障碍域的MSDN's description

    如果成员嵌套在其他类型中,则其可访问域 由成员的可访问性级别和 直接包含类型的可访问域。

    如果包装类型Programinternal,那么嵌套类型Bpublic 将具有匹配Program 的可访问性,因此它被视为internal 并且不会引发编译器错误.

    【讨论】:

    • 是的,现在失败了。我把它们放在程序课之外。感谢您的帮助。
    • @FaisalHafeez 我想我在 C# 规范中找到了描述这种行为的条目。好问题!
    • 很好地使用了这里的规范。
    • @EricLippert 我向最好的人学习。顺便说一句,即使我还没有时间完成它,我也彻底享受了带注释的 C# 规范精装本。 :)
    猜你喜欢
    • 2012-10-27
    • 1970-01-01
    • 1970-01-01
    • 2011-09-07
    • 2023-03-24
    相关资源
    最近更新 更多