反射
反射
定义 :查看和操作元数据的操作 ;
原理: 利用元数据(包括) ,获取类型的完整描述'
特点: 可以获取类型所有的成员和方法,无论他们是否是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>(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;
但是需要创建代理,通用的方案是结合泛型
通过表达式创建委托
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?