一个内部类中的公共成员和内部成员是什么?

87

好的,这可能是一个有点愚蠢的问题,显然有明显的答案,但我很好奇是否有任何微妙之处被忽略了。

在一个internal类中声明的public成员和在一个internal类中声明的internal成员之间,在可见性/可用性方面是否有任何区别?

即:

internal class Foo
{
    public void Bar()
    {
    }
}

而且

internal class Foo
{
    internal void Bar()
    {
    }
}
如果你在声明方法时同时使用了 publicvirtual,然后在一个继承类中覆盖了该方法并且该继承类也是 public 的,那么使用这个修饰符的原因就很清楚了。但是,这是唯一的情况吗...我是否遗漏了其他情况?

4
如果你将方法声明为public且virtual,然后在一个公共的派生类中重写它, 那么当你试图增加可见性时就会出现错误提示声"meeeep!"。你只能减少可见性, 也就是说,你可以创建一个公共类的派生类,该类是内部的(甚至可以是嵌套和私有的)。 - springy76
5
注意Google员工:这个几乎重复的问题包含另一个特别好的答案。 - Michael Richardson
5个回答

68

考虑以下情况:

public interface IBar { void Bar(); }
internal class C : IBar
{
    public void Bar() { }
}

在这里,C.Bar不能被标记为internal(内部的);因为这样做是错误的,因为C.Bar可以被D.GetBar()的调用者访问:

public class D
{
    public static IBar GetBar() { return new C(); } 
}

一位评论者提出了一个跟进问题:显式实现接口方法是否被认为是公共的还是私有的?(C#不允许在显式实现上放置访问修饰符。)

退一步,想想成员中到底哪些部分是“公共的”或“私有的”:人们会误认为像“私有意味着一个方法无法从类外部调用”这样的说法是正确的,但其实并不是;类可以将委托传递给一个私有方法,并将其传递给任何人,然后他们就可以调用一个私有方法。

相反,可访问性决定了一个事物的名称可以在哪里使用!显式接口实现根本没有添加名称到类声明空间中;它们只能通过接口按名称引用,而不能通过类引用。 认为显式接口实现是公共的私有的真的没有任何意义,因为它们没有一个你可以引用的名称。


1
谢谢Eric,这是另一个很好的例子。因此,在internal类中允许使用publicinternal修饰符的原因是有效地实现接口和类继承。在其他情况下,它们似乎是等效的。 - Noldorin
9
Eric也在stackoverflow上回答了一个几乎相同的问题,网址是:https://dev59.com/xGox5IYBdhLWcg3wSCfk#9302642。他在帖子中提供了额外的细节,为上面的回答增添了相当多的实质内容。 - Chris

52

当在一个 internal 类中时,public 成员仍然只是 internal

来自 MSDN:

成员的访问级别永远不能超过其包含类型的访问级别。例如,在内部类型中声明的公共方法只有内部可访问性。

这样想,我要访问一个 public 属性在……?一个我看不到的类中? :)

Eric 的回答在这种情况下非常重要,如果它通过接口而不是直接暴露,那么确实会有所不同,这取决于你正在处理的成员是否处于该情况中。


是的,这确实是我的想法,除了Eric指出的情况(以及我原来问题中提到的情况)。 - Noldorin
当您使用反射时,这也会产生影响。默认的无参数方法(如Type.GetMethods())仅返回公共成员。而内部类中的公共方法仍然知道它是公共的。 - springy76
2
成员的可访问性永远不能超过其包含类型的可访问性。虽然这对某些情况成立,但是一个私有类的公共成员显然比私有类的私有成员具有更广泛的范围(前者适用于整个项目,后者仅适用于类)。 - Deanna
@Deanna 是的...但那并不意味着前面的陈述是错误的,你正在比较同级而不是容器 - 可以访问的位置不会改变,因为你无法从外部访问私有类容器中的公共成员。 - Nick Craver
那么,如果我将我的类定义为“internal”,那么我的成员变量也应该改为“internal”吗?还是应该让它们保持public不变? - paraJdox1

3

刚刚遇到另一个例子,当在WPF的XAML中使用时,这两者之间确实存在差异。

XAML:

<Button Tag="{x:Static vm:Foo+Bar.e1}" />

使用 internal 枚举编写的代码可以成功编译:

internal class Foo
{
    internal enum Bar
    {
        e1,
        e2,
    }
}

但是令人惊讶的是,将其更改为public会导致错误:

internal class Foo
{
    public enum Bar
    {
        e1,
        e2,
    }
}

最后一个例子会产生编译错误:

error MC3064: 仅公共或内部类可以在标记内使用。“Bar”类型不是公共或内部的。

很遗憾,我无法解释在这种情况下public哪里出了问题。我的猜测是“只是因为WPF那样工作”。将嵌套类的修饰符更改为internal以消除错误。

谢谢您!我永远不会猜到我的XAML出了什么问题。 - torvin

2

internal类的public成员可以覆盖public基类的成员,因此它们会更加暴露......虽然是间接的。


1

如果涉及到反射,成员是否为公共成员就很重要:

例如,您甚至可以将嵌套的私有类传递给 WPF 绑定,绑定将像通常一样针对公共属性工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接