第 18 章 自省和元数据 反射和元数据
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
正如我们在第 17 章中看到的,C# 程序编译成一个程序集,其中包括元数据、编译代码和资源。在运行时检查元数据和编译代码称为反射。
汇编中的编译代码几乎包含原始源代码的所有内容。有些信息会丢失,如局部变量名、注释和预处理器指令。不过,反射可以访问几乎所有其他内容,甚至可以编写反编译器。
.NET中的许多服务(如动态绑定、序列化和数据绑定)都依赖于元数据的存在。您自己的程序也可以利用这些元数据,甚至使用自定义属性扩展新信息。System.Reflection 命名空间包含反射 API。通过System.Reflection.Emit 命名空间中的类,还可以在运行时以中间语言(IL)动态创建新的元数据和可执行指令。
本章的示例假定您导入了System 和System.Reflection 以及System.Reflection.Emit 命名空间。
备注
当我们在本章中使用 "动态 "一词时,我们指的是使用反射来执行某些任务,而这些任务的类型安全只有在运行时才能执行。这在原理上类似于通过 C# 的dynamic 关键字进行动态绑定,尽管机制和功能有所不同。
动态绑定更易于使用,它采用动态语言运行时(DLR)来实现动态语言的互操作性。反射的使用相对笨拙,但它在使用 CLR 时更加灵活。例如,通过反射,您可以获取类型和成员的列表,实例化名称来自字符串的对象,以及即时构建程序集。
反映型和激活型
在本节中,我们将研究如何获取Type ,检查其元数据,并使用它动态实例化一个对象。
获取类型
System.Type 的一个实例代表一个类型的元数据。由于 被广泛使用,因此它位于 命名空间,而不是 命名空间。Type System System.Reflection
您可以在任何对象上调用GetType 或使用 C# 的typeof 操作符来获取System.Type 的实例:
Type t1 = DateTime.Now.GetType(); // Type obtained at runtime Type t2 = typeof (DateTime); // Type obtained at compile time
您可以使用typeof 获取数组类型和泛型类型,如下所示:
Type t3 = typeof (DateTime[]); // 1-d Array type Type t4 = typeof (DateTime[,]); // 2-d Array type Type t5 = typeof (Dictionary<int,int>); // Closed generic type Type t6 = typeof (Dictionary<,>); // Unbound generic type
您也可以通过名称检索Type 。如果您有对其Assembly 的引用,请调用Assembly.GetType (我们将在"反映程序集 "一节中进一步介绍):
Type t = Assembly.GetExecutingAssembly().GetType ("Demos.TestProgram");
如果没有Assembly 对象,可以通过程序集限定名称(类型全名后跟程序集全名或部分限定名称)获取类型。程序集会隐式加载,就像调用Assembly.Load(string) 一样:
Type ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access