一、反射的基本信息
反射使你能够获取有关加载的程序集和其中定义的类型的信息,同时可以在运行时创建、调用和访问类型实例。
反射提供封装程序集、模块和类型的对象。可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
那么什么是程序集呢?
程序集包含模块、模块包含类型,而类型包含成员。在 .NET Core 和 .NET Framework 中,可以从一个或多个源代码文件生成程序集,而程序集又可以包含一个或多个模块。
程序集具有以下属性:
-
程序集以 .exe 或 .dll 文件的形式实现。
-
对于面向 .NET Framework 的库,可以通过将程序集放入全局程序集缓存 (GAC),在应用程序之间共享程序集。必须先对程序集进行强命名,然后才能将它们包含到 GAC 中。有关详细信息,请参阅具有强名称的程序集。
-
只有在需要使用时才会将程序集加载到内存中。如果未使用程序集,则不加载。也就是说,使用程序集,可以在大型项目中高效管理资源。
-
可以使用反射,以编程方式获取程序集的相关信息。
-
你可以加载一个程序集,以使用 .NET Core 中的 MetadataLoadContext 类以及 .NET Core 和 .NET Framework 中的 Assembly.ReflectionOnlyLoad 或 Assembly.ReflectionOnlyLoadFrom 方法来检查该程序集。
公共语言运行时中的程序集
程序集向公共语言运行时(CLR)提供了注意类型实现代码所需的信息。对于运行时,类型不存在于程序集上下文之外。
程序集定义以下信息:
-
公共语言运行时执行的代码,每个程序集只能有一个入口点:DllMain、WinMain 或 Main。
-
安全边界。程序集就是在其中请求和授予权限的单元。
-
类型边界。每一类型的标识均包括该类型所驻留的程序集的名称。在一个程序集的范围中加载的称为 MyType 的类型不同于在另一个程序集范围中加载的称为 MyType 的类型。
-
引用范围边界。程序集清单包含用于解析类型和满足资源请求的元数据。该清单指定要在程序集外公开的类型和资源,并枚举它所依赖的其他程序集。除非可迁移可执行 (PE) 文件中的 Microsoft 中间语言 (MSIL) 代码具有相关的程序集清单,否则不执行此代码。
-
版本边界。程序集是公共语言运行时中无版本冲突的最小单元。同一程序集中的所有类型和资源均会被版本化为一个单元。程序集清单描述你为任何依赖项程序集所指定的版本依赖性。
-
部署单元。当一个应用程序启动时,只有该应用程序最初调用的程序集必须存在。其他程序集(例如,包含本地化资源或实用工具类的程序集)可以按需检索。 这样,应用在第一次下载时就会比较精简。
-
并行执行单元。
Module(模块)
模块是可移植的可执行文件,以.dll 或 .exe文件实现,由一个或多个类和接口组成。 单个模块可包含多个命名空间,而一个命名空间可跨越多个模块。
二、反射的使用
使用反射,如果事先知道对象名称,可以用 typeof
,如果知道某个实例,可以用 .GetType()
获取某个实例的 Type
,如果都不知道,或者想知道某个程序集内所有的类,可以先加载程序集,然后获取某个具体的 Type
对象,也可以获取该程序集内部所有的 Type
对象,如果要设置/获取字段、属性的值或者调用实例方法,需要创建该对象的实例,如果仅仅查看属性、字段的名称/类型,方法的名称/参数类型/参数名称/返回值,则不需要创建某一 Type
对象的实例。
typeof() 和 .GetType() 的区别: typeof()一般用于某一类/类型,获取其 Type,不需要其实例化对象,.GetType()是获取某一实例的 Type。
测试:
先创建一类库,名称为SimpleDLL,然后新建3个类,分别为MyClass1、GenericClass、CommonClass
MyClass1类:
public class MyClass1
{
public string name;
public int age;
private string address;
private string MyName {
get; set; }
public int MyAge {
get; set; }
private string MyAddress {
get; set; }
public MyClass1()
{
Console.WriteLine("这是公共的无参构造函数");
}
public MyClass1(int m)
{
Console.WriteLine("这是公共的有参构造函数,参数具有 {0} 类型", m.GetType());
}
private MyClass1(int m, int n)
{
Console.WriteLine("这是私有的有参构造函数,参数具有 {0} 和 {1} 类型", m.GetType(), n.GetType());
}
public void Test1()
{
Console.WriteLine("这是 Test1 方法");
}
public void Test2(int m)
{
Console.WriteLine("这是 Test2 方法,参数具有 {0} 类型", m.GetType());
}
public void Test3(int m, int n)
{
Console.WriteLine("这是 Test3 方法,参数具有 {0} 和 {1} 类型", m.GetType(), n.GetType());
}
public void Test3(string m, string n)
{
Console.WriteLine("这是 Test3 方法,参数具有 {0} 和 {1} 类型", m.GetType(), n.GetType());
}
private void Tset4()
{
Console.WriteLine("这是私有方法");
}
private void Test5(int m)
{
Console.WriteLine("这是私有方法,参数具有 {0} 类型", m.GetType());
}
}
GenericClass类:
/// <summary>
/// 泛型类
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="W"></typeparam>
public class GenericClass<T