反射的常用API
加载程序集
Assembly assembly = Assembly.Load("程序集名称"); // 从前目录加载程序集,提供程序集名称,无后缀
Assembly assembly = Assembly.LoadFile("程序集完整路径"); // 加载指定路径的程序集,需要提供完整的路径(绝对路径)
Assembly assembly = Assembly.LoadFrom("程序集路径"); //加载程序集,可以是相对路径,也可以是绝对路径(需要后缀)
注意事项
- 通常来说,一个项目一个assembly,即一个项目编译后得到一个dll或者exe(当程序有其他项目的依赖时会同时编译其他项目并将生成的dll拷贝至当前目录,看起来有多个dll)
- 反射加载assemblly,如果加载的程序集有依赖项,则需要依赖项需要一同拷贝至当前项目,虽然不用使用Assembly加载,但是找不到依赖项运行时会抛异常
获取类型
Type的基本单位是class,即一个类一个Type
// 获取所有公开类
Type[] types = assembly.GetExportedTypes();
// 获取指定类
Type type = assembly.GetType("完整类名");// 提供完整类名,包括命名空间
注意事项:泛型类的类名为:类名`泛型参数个数,即:
public class GenericExample<T>
{
// 提供的类名为:GenericExample`1
}
泛型类获取后需要为其指定泛型的数据类型才能使用,这个在实例化对象的地方写
实例化对象
实例化对象使用Activator.CreateInstance();
方法,这个方法有多个重载,用于不同的情况
// 调用无参构造函数,使用Activator.CreateInstance()实例化的对象为object类型,当需要通过点的方式使用其内部定义的属性和方法需要先进行类型转换
object oExample = Activator.CreateInstance(type);
// 调用无参非public构造函数,需要特别注意,这种方式可以破坏单例模式,即可以使用私有构造函数实例化对象
object oExample = Activator.CreateInstance(type, true);
// 调用构造函数,参数由object数组指定,在本例中,调用接受一个int的构造函数
object oExample = Activator.CreateInstance(type, new object[] { 123 });
// 当实例化泛型类时,需要先调用MakeGenericType指定泛型类的泛型参数类型
// MakeGenericType方法接收一个Type数组,传递类型列表,并返回一个新的类型,指定了泛型类具体类型的Type才能实例化对象
Type type = assembly.GetType("Example.GenericExample`1");
Type newType = type.MakeGenericType(new Type[] { typeof(int) });
object oExample = Activator.CreateInstance(newType);
使用对象
使用方法
// 以下所有type均是Type type = assembly.GetType("完整类名");中得到的type
// oExample为创建的实例Activator.CreateInstance(type)
// 使用普通无参方法
// 通过方法名取得方法
MethodInfo method = type.GetMethod("Change");
// 通过Invoke调用,第一个参数为执行方法的对象实例,第二个参数为方法的参数
method.Invoke(oExample, null);
// 参数也可以为空object数组,效果相同
method.Invoke(oExample, new object[] {});
// 使用普通带参数方法
MethodInfo method = type.GetMethod("Change");
// 方法参数由object数组传递,如果方法有多个重载版本,则会自动根据object数组中存储的数据类型进行匹配
method.Invoke(oExample, new object[] { 123 });
// 使用静态方法
MethodInfo method = type.GetMethod("Change");
// 调用静态方法的方式与普通方法
method.Invoke(oExample, new object[] { "追风筝的人" });
// 静态方法因为不需要实例,所以可以在指定实例时赋值null
method.Invoke(null, new object[] { "麦田里的守望者" });
// 使用私有方法
// 使用私有方法需要使用BindingFlags.Instance | BindingFlags.NonPublic标注
MethodInfo method = type.GetMethod("PrivateChange", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(oExample, new object[] { "平凡的世界" });
// 使用泛型方法
MethodInfo method = newType.GetMethod("Change"); //泛型方法只写方法名,不需要跟`1泛型参数个数
// 使用泛型方法与前面加载泛型类类似,需要使用MakeGenericMethod指定泛型参数的具体类型
MethodInfo methodNew = method.MakeGenericMethod(new Type[] { typeof(string)});
methodNew.Invoke(oExample, new object[] {"血色浪漫"});
使用属性/字段
// 以下所有type均是Type type = assembly.GetType("完整类名");中得到的type
// oExample为创建的实例Activator.CreateInstance(type)
// 获取所有属性
PropertyInfo[] property = type.GetProperties();
// 获取指定名称属性的值,GetValue接收获取值的对象
object value = type.GetProperty("属性名").GetValue(oExample)
// 设置指定名称属性的值,SetValue接收设置值的对象和设置的值
type.GetProperty("Id").SetValue(oExample, value);
// 获取所有字段
FieldInfo[] fieldInfos = type.GetFields();
// 获取指定名称字段的值,GetValue接收获取值的对象
object value = type.GetField("字段名").GetValue(oExample);
// 设置指定名称字段的值,SetValue接收设置值的对象和设置的值
type.GetField("Id").SetValue(oExample, value);