C#中所有类型和类型成员都具有可访问性级别,用来控制是否可以在其他代码中使用它们。
一、直接在命名空间中声明(区别于内部类或内部结构)的类或结构
这种情况,可以用public,internal关键字进行访问修饰。
public:对类或结构的访问没有限制。
internal(默认):只能在当前程序集访问。可以使用 InternalsVisibleToAttribute 特性使其他某些程序集能够访问internal类型。
internal的访问域是整个程序集,不是整个命名空间,因为一个程序集可以包含多个命名空间,对程序集的简单理解就是编译后生成的exe文件或dll文件。
注意:
a.派生类的可访问性不能高于其基类型。
换句话说,不能有从内部类 A 派生的公共类 B。 如果允许这种情况,将会使 A 成为公共类,因为 A 的所有受保护的成员或内部成员都可以从派生类访问。
二、 类或结构的成员
可以利用public,internal,protected,private 4个关键字设置5种访问级别:
1.public
无访问限制。
2.internal protected
可以理解为internal或protected,其访问域是internal和protected访问域的并集。
(结构的成员不可使用,因为结构不可被继承,所以谈不上protected)
3.internal
当前程序集访问。
4.protected
在同一类或子类内的代码可以访问,即使子类在不同的程序集。
(同样的,不适用于结构中的成员)
5.private(默认)
只有在同一类或结构内的代码可以访问。
这里需要明确“同一类或结构内的代码”的意思,先看看下面的代码:
class C
{
class C1 {
int a = 0;
void f1()
{
C2 c = new C2();//可以访问C2,因为C2内可以访问一切C类内可以访问的东西(我个人的理解)
C2.C21 c = new C2.C21()//报错,不可访问C21,因为C21不是C1的成员
}
}
class C2
{
protected class C21
{
void f2()
{
C1 c = new C1();//可以访问C1,因为C21内可以访问一切C2类内可以访问的东西(我个人的理解)
int i = c.a;//报错,不可访问c的私有成员a
}
}
}
class C3 : C2
{
void f3()
{
C21 c = new C21();//可以访问C2受保护的成员C21,因为C3继承了C2
}
}
}
f2可以访问C1是因为C21和C1都在C的内部吗?如果是这样,那为什么f1不可以访问C21。
我觉得考虑private和protected中“同一类内的代码”的含义,应该是不能跨越多个类的,即使是内部类。
内部类仅仅作为外部类的成员,所以外部类的方法属性等毫无疑问地是可以访问此内部类的,然而内部类的方法,属性等可以访问外部类的成员,并不是因为它们都在此外部类内,是因为内部类可以访问外部类一切可以访问的东西,这是我个人的理解。
注意:
a.析构函数和静态的构造函数不能具有可访问性修饰符,因为这些成员是由CLR直接调用的。
b.成员的实际访问域 是 其访问修饰符赋予的访问域 与 成员所在类或结构的访问域 的交集。
也就是说,你只有先访问到了类或结构,才有可能访问其中的成员。
c.任何成员(字段、 属性或事件)的类型必须至少与该成员本身一样具备可访问性。
也就是说,在可以访问到该成员的地方,起码要能够访问到该成员的类型吧。
d.同理,任何能够访问到成员(索引器,方法)的地方,起码要能够访问成员的参数和返回值
e.自定义的运算符必须为public。
三、内部类或结构
类与类,类与结构,结构与结构之间可以相互嵌套。内部类或结构相当于外部类或结构的成员,所以以上的 类或结构的成员的叙述 适用于内部类或结构。
四、接口/枚举/委托
接口的访问权限默认为internal。访问修饰符不能应用于接口成员,接口成员的访问权限默认是public。
枚举的访问权限默认为internal。访问修饰符不能应用于枚举成员,枚举成员的访问权限默认是public。
委托在命名空间中声明是默认具有internal访问权限,在类或结构的内部声明时默认具有private的访问权限。