6.2 类型的可见性
要定义文件范围的类型时,可将类型的可见性指定为public或internal。
public类型不仅对定义程序集中的所有代码可见,还对其他程序集中的代码可见。
internal类型则仅对定义程序集中的所有代码可见,对其他程序集中的代码不可见。
定义类型时不显式指定可见性,C#编译器会帮你指定为internal。
//public即可有本程序集也可由其他程序集的代码访问 public class ThisIsAPublicType{} //internal,只可有本程序集的代码访问 internal class ThisisAnInternalType{} //没有显式声明,默认为internal class ThisIsAlsoAnInternalType{}
友元程序集
将工具类型定义为internal,同时仍然允许其他人访问这些类型。
CLR和C#通过友元程序集friend assembly 提供这方面的支持。
一个程序集的代码对另一个程序集中的内部类型进行单元测试时,友元程序集功能也能派上用场。
生成程序集时,可用System.Runtime.CompilerServices命名空间中的InternalsVisibleTo特性标明它认为是友元的其他程序集。
该特性获取标识友元程序集名称和公钥的字符串参数。
注意,当程序集认了友元之后,友元程序集就能访问该程序集中的所有internal类型,以及这些类型的internal成员。
下例展示一个程序集如何将两个强命名程序集“Wintellect”和“Microsoft”指定为友元程序集
using System; using System.Runtime.CompilerServices; //当前程序集中的internal类型可由以下两个程序集中的任何代码访问 [assembly:InernalsVisibleTo("Wintellect,PublicKey=12345678...90abcdef")] [assembly:InernalsVisibleTo("Microsoft,PublicKey=b77a5c56...1934e089")] internal sealed class SomeInternalType{} internal sealed class AnotherInternalType{}
从友元程序集访问上述程序集的internal类型很容易。
例如,下面展示了公钥相符的友元程序集Wintellect如何访问上述程序集的internal类型SomeInternalType
internal sealed class Foo { private static Object SomeMethod() { //这个Wintellect程序集能访问另一个程序集的internal类型 //就好像那是public SomeInternalType sit=new SomeInternalType(); return sit; } }
由于程序集中的类型的internal成员能从友元程序集访问,
所以要慎重考虑类型成员的可访问性,以及要将哪些程序集声明为友元。
注意,C#编译器在边缘友元程序集(不含InternalsVisibleTo特性的程序集)时,要求使用编译开关/out:<file>。
使用这个编译开关的原因在于,编译器需要知道准备编译的程序集的名称,从而判断生成的程序集时不是友元程序集。
事实上,在代码结束编译之前,C#是不知道输出文件名的。
同样的如果使用C#编译器的/t:module开关来编译模块(而不是编译成程序集),而且该模块将成为某个友元程序集的一部分,
那么还需要使用C#编译器的/moduleassemblyname:<string>开关来编译该模块,他告诉编译器该模块将成为哪个程序集的一部分,
使编译器设置模块中的代码,使他们能访问另一个程序集中的internal类型。