C#访问修饰符有哪些(附带实例)
C# 程序中,为了提高封装性,类型或类型成员可以在声明中添加下表六个访问权限修饰符之一来限制其他类型和其他程序集对它的访问:
例如,Class2 可以从本程序集外访问,而 Class1 不可以:
再例如,ClassB 的字段 x 可以被本程序集的其他类型访问,而 ClassA 的则不可以:
再例如,Subclass 中的函数可以调用 Bar 但是不能调用 Foo:
如果友元程序集有强名称,必须指定其完整的 160 字节公钥:
可以使用 LINQ 查询的方式从强命名的程序集中提取完整的公钥值:
C的(默认)可访问性是 internal,它作为 Foo 的最高访问权限,使 Foo 成为 internal 的。而将 Foo 指定为 public 的原因一般是为了将来将 C 的权限改成 public 时方便进行重构。
编译器会阻止任何不一致的访问权限修饰符。例如,子类可以比基类的访问权限低,但不能比基类的访问权限高:
可访问性修饰符 | 说明 |
---|---|
public | 完全访问权限。这是枚举类型成员或接口成员隐含的可访问性。 |
internal | 仅可以在程序集内访问,或供友元程序集访问。这是非嵌套类型的默认可访问性。 |
private | 仅可以在包含类型中访问。这是类或者结构体成员的默认可访问性。 |
protected | 仅可以在包含类型或子类中访问。 |
protected internal | protected 和 internal 可访问性的并集。protected internal 修饰的成员在任意一种修饰符限定下都能够访问。 |
private protected | 从 C# 7.2 开始支持。protected 和 internal 可访问性的交集:仅能在定义该成员的类型中或被同一程序集的子类型访问。 |
例如,Class2 可以从本程序集外访问,而 Class1 不可以:
class Class1 { } // Class1 is internal (default) public class Class2 { }
再例如,ClassB 的字段 x 可以被本程序集的其他类型访问,而 ClassA 的则不可以:
class ClassA { int x; // x is private (default) } class ClassB { internal int x; }
再例如,Subclass 中的函数可以调用 Bar 但是不能调用 Foo:
class BaseClass { void Foo() { } // Foo is private (default) protected void Bar() { } } class SubClass : BaseClass { void Test1() { Foo(); } // Error - cannot access Foo void Test2() { Bar(); } // OK }
友元程序集
在一些高级的场景中,添加 System.Runtime.CompilerServices.InternalsVisibleTo 程序集特性就可以将 internal 成员提供给其他友元程序集访问。可以用如下方法指定友元程序集:[assembly: InternalsVisibleTo("Friend")]
如果友元程序集有强名称,必须指定其完整的 160 字节公钥:
[assembly: InternalsVisibleTo("StrongFriend, PublicKey=0024f000048c...")]
可以使用 LINQ 查询的方式从强命名的程序集中提取完整的公钥值:
string key = string.Join("", Assembly.GetExecutingAssembly() .GetName() .GetPublicKey() .Select(b => b.ToString("x2")));
可访问性上限
类型的可访问性是它内部声明成员可访问性的上限。关于可访问性上限,最常用的示例是 internal 类型中的 public 成员。例如:class C { public void Foo() { } }
C的(默认)可访问性是 internal,它作为 Foo 的最高访问权限,使 Foo 成为 internal 的。而将 Foo 指定为 public 的原因一般是为了将来将 C 的权限改成 public 时方便进行重构。
访问权限修饰符的限制
当重写基类的函数时,重写函数的可访问性必须一致,例如:class BaseClass { protected virtual void Foo() { } } class SubClass1 : BaseClass { protected override void Foo() { } // OK } class SubClass2 : BaseClass { public override void Foo() { } // Error }若在另外一个程序集中重写 protected internal 方法,则重写方法必须为 protected。这是上述规则中的一个例外情况。
编译器会阻止任何不一致的访问权限修饰符。例如,子类可以比基类的访问权限低,但不能比基类的访问权限高:
internal class A { } public class B : A { } // Error