C#中的默认访问修饰符是什么?

460
类、方法、成员、构造函数、委托和接口的默认访问修饰符是什么?
10个回答

570

C#中所有成员的默认访问权限是“你可以声明的最受限制的访问权限”

例如:

namespace MyCompany
{
    class Outer
    {
        void Foo() {}
        class Inner {}
    }
}

等同于

namespace MyCompany
{
    internal class Outer
    {
        private void Foo() {}
        private class Inner {}
    }
}

这种情况的一个例外是,使属性的一部分(通常是setter)比属性本身声明的可访问性更受限制:
public string Name
{
    get { ... }
    private set { ... } // This isn't the default, have to do it explicitly
}

以下是C# 3.0规范中的相关内容(第3.5.1节):
根据成员声明所在的上下文,只允许使用特定类型的声明可访问性。此外,当成员声明不包括任何访问修饰符时,声明所在的上下文决定了默认的声明可访问性。
- 命名空间隐式具有public声明的可访问性。命名空间声明中不允许使用访问修饰符。 - 编译单元或命名空间中声明的类型可以具有public或internal声明的可访问性,并且默认为internal声明的可访问性。 - 类成员可以具有五种声明可访问性中的任何一种,并且默认为private声明的可访问性。(请注意,作为类成员声明的类型可以具有五种声明可访问性中的任何一种,而作为命名空间成员声明的类型只能具有public或internal声明的可访问性。) - 结构体成员可以具有public、internal或private声明的可访问性,并且默认为private声明的可访问性,因为结构体被隐式地标记为sealed。结构体中引入的结构体成员(即未由该结构体继承的结构体成员)不能具有protected或protected internal声明的可访问性。(请注意,作为结构体成员声明的类型可以具有public、internal或private声明的可访问性,而作为命名空间成员声明的类型只能具有public或internal声明的可访问性。) - 接口成员隐式具有public声明的可访问性。接口成员声明中不允许使用访问修饰符。 - 枚举成员隐式具有public声明的可访问性。枚举成员声明中不允许使用访问修饰符。
(请注意,嵌套类型将归入“类成员”或“结构体成员”部分,并因此默认为私有可见性。)

2
注意:在C# 8中,接口允许使用访问修饰符,默认为public。 - Ivan Montilla

184
top level class: internal
method: private
members (unless an interface or enum): private (including nested classes)
members (of interface or enum): public
constructor: private (note that if no constructor is explicitly defined, a public default constructor will be automatically defined)
delegate: internal
interface: internal
explicitly implemented interface member: public!

18
如果一个类也是一个成员(因为它是一个嵌套类型),那么这并没有明确它默认为私有。另外,接口和枚举的成员始终是公共的。 - Jon Skeet
1
@niry 不,它不是私有的。它是公共的。它只是没有在实现类型中获得一个插槽,所以如果 class Foo : IFoo { IFoo.M() {} } ... Foo a = new Foo();,你不能使用 a.M() 访问 M,但是你可以使用 (a as IFoo).M() 访问它。(查看规范以获取更多详细信息) - M.Stramm
由于我们没有为接口方法指定任何访问修饰符,因此它们始终是公共的。 - Jay Ponkia

159

简短回答:最小可能访问权限(参考Jon Skeet的答案)。

长篇回答:

非嵌套类型、枚举和委托的可访问性只能具有内部或公共可访问性

                     | Default   | Permitted declared accessibilities
------------------------------------------------------------------
namespace            | public    | none (always implicitly public)

enum                 | public    | public, internal

interface            | internal  | public, internal

class                | internal  | public, internal

struct               | internal  | public, internal

delegate             | internal  | public, internal

嵌套类型和成员的可访问性

                     | Default   | Permitted declared accessibilities
------------------------------------------------------------------
namespace            | public    | none (always implicitly public)

enum                 | public    | All¹

interface            | public    | All¹

class                | private   | All¹

struct               | private   | public, internal, private²

delegate             | private   | All¹

constructor          | private   | All¹

enum member          | public    | none (always implicitly public)

interface member     | public    | none (always implicitly public)
     
method               | private   | All¹

field                | private   | All¹

user-defined operator| none      | public (must be declared public)

嵌套类型的可访问性取决于其可访问性域,该域由成员的声明可访问性和直接包含类型的可访问性域确定。但是嵌套类型的可访问性域不能超过包含类型的可访问性域。

注意:CIL(Common Intermediate Language)还提供了 protected and internal(而不仅仅是现有的 protected 或 internal),但据我所知目前在 C# 中不可用。


参见:

http://msdn.microsoft.com/en-us/library/ba0a1yw2.aspx
http://msdn.microsoft.com/en-us/library/ms173121.aspx
http://msdn.microsoft.com/en-us/library/cx03xt0t.aspx
(我真爱微软的 URL……)


1
这个答案部分是不正确的。非嵌套枚举也可以是 internal 的。嵌套枚举和接口可以是从 public 到 private 的任何访问级别。 - Saul
如果您对自己的理解有信心,可以随意编辑。我不再了解C#... - Ben Aston
1
使用C# 8,我们现在也可以拥有私有和受保护的接口成员。请查看https://jeremybytes.blogspot.com/2019/11/c-8-interfaces-public-private-and.html。 - erhan355

12
请查看访问修饰符(C# 编程指南)

类和结构体的可访问性

在命名空间内直接声明的类和结构体(也就是没有嵌套在其他类或结构体中的)可以是 public 或 internal。如果没有指定访问修饰符,则默认为 internal。

结构体成员(包括嵌套类和结构体)可以声明为 public、internal 或 private。类成员(包括嵌套类和结构体)可以是 public、protected internal、protected、internal、private protected 或 private。类成员和结构体成员(包括嵌套类和结构体)的访问级别默认为 private。私有嵌套类型无法从包含它们的类型外部访问。

派生类的可访问性不能比其基类型更高。也就是说,您不能有一个从 internal 类 A 派生的 public 类 B。如果允许这样做,A 的所有受保护或内部成员将可从派生类访问,效果就是将 A 设为 public。

您可以使用 InternalsVisibleToAttribute 来启用特定的其他程序集访问您的内部类型。有关更多信息,请参见友元程序集。

类和结构体成员的可访问性

类成员(包括嵌套类和结构体)可以用任何一种访问修饰符声明。结构体成员不能声明为 protected,因为结构体不支持继承。

通常,成员的访问性不能比包含它的类型的访问性更高。但是,如果成员实现了在公共基类中定义的接口方法或重写虚方法,则来自内部类的公共成员可能会从程序集外部访问。

任何作为字段、属性或事件的成员类型,必须至少与该成员本身具有相同的访问权限。类似地,任何作为方法、索引器或委托的成员的返回类型和参数类型都必须至少与该成员本身具有相同的访问权限。例如,如果C是公共的,则不能有返回类C的公共方法M。同样,如果A被声明为私有的,则不能有类型为A的受保护属性。
用户定义的运算符必须始终声明为public和static。更多信息请参见运算符重载。
Finalizers不能有访问权限修饰符。
其他类型
在命名空间中直接声明的接口可以声明为public或internal,就像类和结构体一样,默认情况下,接口默认为internal访问权限。接口成员始终是public,因为接口的目的是使其他类型能够访问类或结构体。不能将访问修饰符应用于接口成员。
枚举成员始终是public的,不能应用访问修饰符。
委托的行为类似于类和结构体。默认情况下,当在命名空间中直接声明时,它们具有internal访问权限,在嵌套时具有private访问权限。

11

类默认情况下是内部的(Internal)

  • 类成员默认情况下是私有的(private)

接口默认情况下是内部的(Internal)

  • 接口成员默认情况下是公共的(public)。(接口不允许我们指定任何类型的成员可访问性。)

    注意: 如果您尝试为接口成员指定任何访问修饰符,则会显示编译错误。

结构体默认情况下是内部的(Internal)

  • 结构体成员默认情况下是私有的(private)

6
最简单的答案如下.....
所有C#中的成员默认情况下都采用最不可访问的修饰符。
这就是为什么一个程序集中的所有顶级类默认都是"internal",这意味着它们对于所在的程序集是公开的,但对于外部程序集来说是私有的或无法访问的。顶级类的唯一其他选项是public,这是更可访问的。对于嵌套类型,除了一些罕见的例外情况(如枚举和接口的成员只能是public),其余都是private。以下是一些示例。
C#中有两种访问修饰符的类别。
顶级...
class MyClass {
    ...
}

...和会员级别(在另一个类内部等)

class MyClass {
    class MySubClass {
        ...
    }
}

每个人都有自己不同的默认设置。一般来说,所有顶级类型可以是“internal”(默认值,与无访问修饰符相同,并且不能从外部程序集访问)或“public”(对程序集和外部程序集开放)。
顶级类型访问修饰符
在顶级类、结构、接口等情况下,默认值都是“internal”,以使用“animal”类作为示例。这意味着它们默认情况下对外部程序集是关闭的:
class Animal{} 等同于 internal class Animal{}
interface Animal{} 等同于 internal interface Animal{}
成员级别类型访问修饰符
在嵌套类和接口(在类型内部)的情况下,默认值通常是“private”,除了接口和枚举是“public”。这通常意味着类中的成员既不能从所在的内部程序集访问,也不能从外部程序集访问。

class Animal{}private class Animal{}是一样的。

interface Animal{}public interface Animal{}是一样的。

请理解,顶级类型也控制着它们内部的成员。所以,如果你将一个顶级访问修饰符internal改为public,那么类内的任何公共成员或受保护的派生成员都可以被外部程序集访问!

请记住,当从控制可访问性的基类派生时,这些规则也可能被打破。但是,如果你假设C#类型的默认值始终是最私有的,那么在不需要更改默认值之前,你就不需要使用自定义访问修饰符。它们已经默认提供了安全性!


6

我想添加一些文档链接。在这里查看更多详细信息

输入图像描述


3
默认情况下,类是 internal 而不是 private。 - Baahubali
1
我在哪里写了私有类? - Asif Mushtaq
1
此表格仅适用于嵌套类型。 - BlueSilver
类默认为内部类,命名空间中的类不能是私有的。但是类中的类(嵌套类)可以是私有的。 - Arun
接口的访问修饰符默认为 Internal - xoxo

1

命名空间级别:internal

类型级别:private


正确的答案,但没有对权威来源的引用,必须盲目信任。 - mins

0

internal 是类的默认访问修饰符。

private 是类成员的默认访问修饰符。


-1

Internal 是默认的修饰符


不适用于类成员 - sleeparrow

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