AC# 程序编译为 DLL 程序集,其中包含已编译的 C# 代码以及运行时的元数据和其他资源。C# 提供了一个反射 API,让我们可以在运行时检查元数据和编译后的代码。
使用反射,可以 -
访问程序集中所有类型的程序集元数据
获取类型及其成员(方法、属性等)的列表
在运行时动态调用类型成员。
仅通过提供名称来实例化对象
构建程序集
在传统程序中,当您将源代码编译为机器代码时,编译器会删除有关代码的所有元数据。但是,由于 C# 是一种在公共语言运行时 (CLR) 中运行的托管语言,因此编译器会保留有关代码的大部分信息。反射允许我们检查程序集中的元数据。
该System.Reflection命名空间包含的所有类和其他类型的反射必需的。您还可以通过 System.Reflection.Emit 命名空间中的类型创建新的元数据并以中间语言 (IL) 发出可执行代码。
System.Type使您可以访问类型的元数据。该对象还包括用于枚举类型实例成员的方法,您可以调用这些方法。
using System; using System.Text; using System.Reflection; var sb = new StringBuilder(); // 在运行时键入 Type t1 = sb.GetType(); Console.WriteLine(t1.FullName); // System.Text.StringBuilder // 编译时输入 Type t2 = typeof (StringBuilder); Console.WriteLine(t2.FullName); // System.Text.StringBuilder
给定对程序集的引用,也可以按名称获取类型。下面的示例使用当前程序集并获取在 Models 命名空间中定义的 Person 类的类型。
Type personType = Assembly.GetExecutingAssembly().GetType("CSharp.Models.Person"); Console.WriteLine(personType.FullName); // CSharp.Models.Person
Type 类有一些有用的属性,您可以使用它们来访问类型的名称、程序集、可见性、基类型等。
using System; using System.Text; using System.Reflection; var sb = new StringBuilder(); // 在运行时键入 Type t1 = sb.GetType(); // What's the type's name? Console.WriteLine(t1.FullName); // System.Text.StringBuilder // What's the type's base type? Console.WriteLine(t1.BaseType); // System.Object // Which assembly is the type defined in? Console.WriteLine(t1.Assembly); // System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e // Is the type public? Console.WriteLine(t1.IsPublic); // True
随着这些特性,还有诸如方法GetProperties(),GetMethods()以及GetFields()提供访问类型的成员。重要的是获得对类型的 Type 对象的引用。有两种方法可以实现这一点 -
object.GetType():
所有类型都包含此功能。它在运行时返回类型
类型(类):
此表达式在编译时获取类型。它在编译时绑定到特定的 Type 实例,并直接将类型作为参数。
System.Reflection命名空间中的类以及命名空间中定义的类System.Type允许您获取有关程序集及其中类型的信息,例如类、接口和值类型。