反射
反射
定义 :查看和操作元数据的操作 ;
原理: 利用元数据(包括) ,获取类型的完整描述'
特点: 可以获取类型所有的成员和方法,无论他们是否是private,甚至还可以修改值,调用私有静态构造函数。
动态加载(也叫晚期绑定);
使用套路
class Program
{
static void Main(string[] args)
{
Person p = new Person();
Type type = p.GetType();
//反射可以获取并调用私有方法
var set_NameMethod = type.GetMethod("set_Name", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
set_NameMethod.Invoke(p, new object[] { "aaa" });
//当方法带有参数时,需要按顺序传递参数的类型
var setNickNameMethod = type.GetMethod("SetNickName", new Type[] { typeof(string), typeof(string) });
setNickNameMethod.Invoke(p, new object[] { "xxx", "jack" });
//方法二,使用InvokeMember 调用方法不常用; Binder参数不能传Null
// type.InvokeMember("SetNickName", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic, null, p, new object[] { "xxx", "jim" });
//调用泛型方法 ,必须要调用 MakeGenericMethod(type)
var genericMethod = type.GetMethod("SetTemperament");
var intSetTemperament = genericMethod.MakeGenericMethod(typeof(int));
intSetTemperament.Invoke(p, new object[] { 100 });
var strSetTemperament = genericMethod.MakeGenericMethod(typeof(string));
strSetTemperament.Invoke(p, new object[] { "Nice" });
//读写实例字段
var field_NickName = type.GetField("_NickName", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
field_NickName.GetValue(p);
field_NickName.SetValue(p, "jack");
//读写静态字段,当是静态字段时,obj参数的值可以传 p 或者 null
var field_MaxAge = type.GetField("_MaxAge", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
field_MaxAge.GetValue(null);
field_MaxAge.SetValue(null, 500);
}
}
public class Person
{
public string Name { get; private set; }
private string _NickName = "xxx";
public static int _MaxAge;
static Person() { _MaxAge = 200; }
public void PrintName() { Console.WriteLine(Name); }
public void SetNickName(string oldName, string newName)
{
if (oldName != _NickName)
{
Console.WriteLine("旧的 _NickName 不正确"); return;
}
_NickName = newName;
}
public object _Temperament;
public void SetTemperament(T temperament)
{
Console.WriteLine($"temperament Type:{temperament.GetType()}");
_Temperament = temperament;
}
}
关于 BingingFlags 常用的值
名称 | 说明 |
---|---|
Instance | 指定实例成员要包括在搜索中。 |
Static | 指定静态成员要包括在搜索中 |
NonPublic | 指定非公共成员要包括在搜索中。 |
DeclaredOnly | 指定只应考虑在所提供类型的层次结构级别上声明的成员。 不考虑继承的成员。 |
常用方法:
方法名称 | 说明 |
---|---|
GetMembers() | 返回为当前 Type 的所有公共成员 |
GetMethods() | 返回为当前 Type 的所有公共方法。 |
GetProperties() | 返回为当前 Type 的所有公共属性。 |
GetFields() | 返回当前 Type 的所有公共字段。 |
GetConstructors() | 返回为当前 Type 定义的所有公共构造函数。 |
上面的几个方法 ,都有对应的 MethodName(BindingFlags) 重载版本 |
性能:
反射调用时比较慢,由于要进行参数校验,和类型对比;大概是直接调用的100倍;
大多数情况下性能:直接调用>委托调用>Emit调用>表达式调用>反射调用>反射后调用DynamicInvoke 。
优化的方法是通过创建代理 ,然后 代理对象.Invoke ,注意是使用delegate.Invoke,而不是delegate.DynamicInvoke;
但是需要创建代理,通用的方案是结合泛型
通过表达式创建委托