反射
大约 16 分钟约 4827 字
反射
反射/反编译工具/高级语言到计算机语言的历程
反射创建对象
IDBHelper dBHelper = new SqlServerHelper();
IDBHelper dBHelper = new MySqlHelper();
dBHelper.Query();Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//dll名称 Assembly assembly1 = Assembly.LoadFile(@"D\MyReflecttion\bin\Debug\net5.0\Business.DB.SqlServer.dll");//dll名称 Assembly assembly2 = Assembly.Load("Business.DB.SqlServer");//dll名称foreach (Type type in assembly.GetTypes()) { Console.WriteLine(type.FullName); foreach (var method in type.GetMethods()) { Console.WriteLine(method.Name); } foreach (var fild in type.GetFields()) { Console.WriteLine(fild.Name); } }Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");object? oInstance = Activator.CreateInstance(type); object? oInstanc1= Activator.CreateInstance("Business.DB.SqlServer.dll", "Business.DB.SqlServer.SqlServerHelper"); //a.oInstance.Query();//报错了: 因为oInstance当做是一个object类型,object类型是没有Query方法;C#语言是一种强类型语言;编译时决定你是什么类型,以左边为准;不能调用是因为编译器不允许;实际类型一定是SqlServerHelper; //b.如果使用dynamic 作为类型的声明,在调用的时候,没有限制; //c.dynamic :动态类型:不是编译时决定类型,避开编译器的检查;运行时决定是什么类型 //d.dynamic dInstance = Activator.CreateInstance(type); //e.dInstance.Query(); ////f.dInstance.Get(); //报错了--因为SqlServerHelper没有Get方法SqlServerHelper helper = (SqlServerHelper)oInstance; //不建议这样转换--如果真实类型不一致--会报报错; IDBHelper helper = oInstance as IDBHelper;//如果类型一直,就转换,如果不一致;就返回nullhelper.Query(); ////经过5步骤;千辛万苦--终于调用到了Query方法; ////问题:反射不是很牛逼吗?无处不在?就这? ////1.代码好多---在面向对象以后,代码多不是事儿; ////2.继承 封装 多态 ////3.代码多久封装//IDBHelper helper1 = SimpleFactory.CreateInstance(); //helper1.Query(); //1.如果公司来了一个新的技术经理:---SqlServer----MySql //2.传统方式,必须要修改代码---必须要重新发布 编译 发布到服务器---步骤就很多 //3.反射实现:断开了对普通类的依赖;依赖于配置文件+接口(抽象) //SqlServer---MySql //a. 按照接口约定实现一个Mysql帮助类库 //b. Copy dll 文件到执行目录下 //c. 修改配置文件 //结果:不同功能的灵活切换---程序的课配置; // 如果经理--MySql--Oracle // 如果一个新的功能还不存在,只需要把功能实现、dll Copy到执行目录下,修改配置文件---不需要停止程序的运行; 扩展一个新的功能进来; // 程序的课可扩展反射黑科技---反射可以做到普通方式做不到的事儿;--反射破坏单例
{ //new Singleton(); Singleton singleton1 = Singleton.GetInstance(); Singleton singleton2 = Singleton.GetInstance(); Singleton singleton3 = Singleton.GetInstance(); Singleton singleton4 = Singleton.GetInstance(); Console.WriteLine(object.ReferenceEquals(singleton1, singleton2)); Console.WriteLine(object.ReferenceEquals(singleton2, singleton3)); Console.WriteLine(object.ReferenceEquals(singleton1, singleton4)); } //new Singleton(); { Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.Singleton"); Singleton singleton1 = (Singleton)Activator.CreateInstance(type, true); Singleton singleton2 = (Singleton)Activator.CreateInstance(type, true); Singleton singleton3 = (Singleton)Activator.CreateInstance(type, true); Singleton singleton4 = (Singleton)Activator.CreateInstance(type, true); Console.WriteLine(object.ReferenceEquals(singleton1, singleton2)); Console.WriteLine(object.ReferenceEquals(singleton2, singleton3)); Console.WriteLine(object.ReferenceEquals(singleton1, singleton4)); }反射调用方法+反射创建对象的升级篇
{ Type type = null; Activator.CreateInstance();//访问的是无参数构造函数创建对象; //如何访问带参数的构造函数呢? Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest"); //a. 调用无参数构造函数的 object noParaObject = Activator.CreateInstance(type); //b. 调用有参数的---需要传递一个object类型的数组作为参数,参数按照从昨往右匹配;严格匹配,按照参数的类型去执行对应的和参数类型匹配的构造函数,如果没有匹配的---报异常 object paraObject = Activator.CreateInstance(type, new object[] { 123 }); object paraObject1 = Activator.CreateInstance(type, new object[] { "纯洁的逗比" }); object paraObject2 = Activator.CreateInstance(type, new object[] { 234, "丸印" }); object paraObject3 = Activator.CreateInstance(type, new object[] { "Richard", 456 }); }//1.获取方法odInfo //2.执行MethodInfo 的Invoke方法,传递方法所在的类的实例对象+参数 { //a. 调用五参数的方法 Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest"); object oInstance = Activator.CreateInstance(type); MethodInfo show1 = type.GetMethod("Show1"); show1.Invoke(oInstance, new object[] { }); show1.Invoke(oInstance, new object[0]); show1.Invoke(oInstance, null); } // b. 调用有参数的方法---重载方法--需要通过方法参数类型类区别方法,传递参数--严格匹配参数类型 { Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest"); object oInstance = Activator.CreateInstance(type); MethodInfo show2 = type.GetMethod("Show2"); show2.Invoke(oInstance, new object[] { 123 MethodInfo show31 = type.GetMethod("Show3", new Type[] { typeof(string), typeof(int) }); show31.Invoke(oInstance, new object[] { "细雨浮萍", 234 MethodInfo show32 = type.GetMethod("Show3", new Type[] { typeof(int) }); show32.Invoke(oInstance, new object[] { 345 MethodInfo show33 = type.GetMethod("Show3", new Type[] { typeof(string) }); show33.Invoke(oInstance, new object[] { "幸福靓装" MethodInfo show34 = type.GetMethod("Show3", new Type[0]); show34.Invoke(oInstance, null); //c. 调用私有方法,在获取方法的时候,加上参数BindingFlags.NonPublic | BindingFlags.Instance { Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest"); object oInstance = Activator.CreateInstance(type); MethodInfo show4 = type.GetMethod("Show4", BindingFlags.NonPublic | BindingFlags.Instance); show4.Invoke(oInstance, new object[] { "String" }); } { ReflectionTest.Show5(); Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest"); object oInstance = Activator.CreateInstance(type); MethodInfo show5 = type.GetMethod("Show5"); show5.Invoke(null, new object[] { "String" }); show5.Invoke(oInstance, new object[] { "String" }); //d. 调用泛型方法: 1. 获取到方法后,先确定类型,严格按照参数类型传递参数就可以正常调用 { //泛型是延迟声明,调用的时候,确定类型 { GenericMethod genericMethod = new GenericMethod(); genericMethod.Show<string, int, DateTime>("", 23, DateTime.Now); } { Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.GenericMethod"); object oInstance = Activator.CreateInstance(type); MethodInfo show = type.GetMethod("Show"); //在执行之前选哟确定是什么类型; MethodInfo genericshow = show.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); genericshow.Invoke(oInstance, new object[] { 123, "暖风昔人", DateTime.Now }); genericshow.Invoke(oInstance, new object[] { "暖风昔人", 123, DateTime.Now //show.Invoke(); //到到底给什么类型呢? 泛型,其实不确定的类型的; } Console.WriteLine(typeof(GenericClass<,,>)); Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.GenericClass`3"); Type generType = type.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); object oInstance = Activator.CreateInstance(generType); MethodInfo show = generType.GetMethod("Show"); show.Invoke(oInstance, new object[] { 123, "赤", DateTime.Now }); } { Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.GenericDouble`1"); Type generType = type.MakeGenericType(new Type[] { typeof(int) }); object oInstance = Activator.CreateInstance(generType); MethodInfo show = generType.GetMethod("Show MethodInfo genericMethod = show.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) }); genericMethod.Invoke(oInstance, new object[] { 123, "鱼儿", DateTime.Now }); } }反射多种应用场景
反射的局限---真的有性能问题---主要损耗性能的是加载dll 的时候会损耗性能
//1.有局限---性能问题 //2.测试用例:普通方式循环100000次创建对象+方法调用: 17毫秒 // 反射方式循环100000次创建对象+方法调用: 6300毫秒---6秒的 //3.第二次执行:普通方式:15毫秒 反射方式:6539毫秒 //4.确实有性能问题:能优化一下?---把动态加载Dll 部分 缓存起来了;每次直接使用加载的dll // 执行结果:普通方式:18面试 反射方式:71毫秒了 //使用反射的建议:1.反射确实有性能问题,2.需要理性对待,就不用吗?当然要用;因为反射的经过优化之后其实性能差也没有差多少的;因为反射能量确实是太多了,大家以后在工作中,可以放心使用; Monitor.Show(); public class Monitor { public static void Show() { Console.WriteLine("*******************Monitor*******************"); long commonTime = 0; long reflectionTime = 0; { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 1000_000; i++) //1000000000 { IDBHelper iDBHelper = new SqlServerHelper(); iDBHelper.Query(); } watch.Stop(); commonTime = watch.ElapsedMilliseconds; } { Stopwatch watch = new Stopwatch(); watch.Start(); Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 动态加载 Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 获取类型 for (int i = 0; i < 1000_000; i++) { //Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 动态加载 //Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 获取类型 object oDBHelper = Activator.CreateInstance(dbHelperType);//3 创建对象 IDBHelper dbHelper = (IDBHelper)oDBHelper;//4 接口强制转换 dbHelper.Query();//5 方法调用 } watch.Stop(); reflectionTime = watch.ElapsedMilliseconds; } Console.WriteLine($"commonTime={commonTime} reflectionTime={reflectionTime}"); } }反射调用字段属性--一个类的内部,除了构造函数。方法----还有其他的很多东西;属性字段
//1.普通方法调用属性字段---简单快捷 //2.反射操作---稍微麻烦点 //3.让我们的程序更加稳定--- //4.如果说People增加一个字段呢?增加一个属性呢?--普通方法就必须要修改代码---重新编译发布----不稳定 //6.反射设置值:好像没啥优势 //7.反射取值:不需要修改代码---代码就更加稳定 //传统方式使用属性和字段 { Console.WriteLine("***********赋值*************"); People people = new People(); people.Id = 134; people.Name = "陈大宝"; people.Age = 25; people.Description = "高级班的VIP学员"; people.Sex = 1; //People people1 = new People() //{ // Id = 134, // Name = "陈大宝", // Age = 25, // Description = "高级班的VIP学员" //}; Console.WriteLine("***********取值*************"); Console.WriteLine($"people.Id={people.Id}"); Console.WriteLine($"people.Name={people.Name}"); Console.WriteLine($"people.Age={people.Age}"); Console.WriteLine($"people.Sex={people.Sex}"); Console.WriteLine($"people.Description={people.Description}"); } Console.WriteLine("***********反射方式*************"); //反射呢?如何给属性字段设置值和取值? { Type type = typeof(People); object pObject = Activator.CreateInstance(type); //pObject.Id=234; foreach (var prop in type.GetProperties()) { //Console.WriteLine(prop.Name); //逐个属性赋值 if (prop.Name.Equals("Id")) { prop.SetValue(pObject, 134); } else if (prop.Name.Equals("Name")) { prop.SetValue(pObject, "陈大宝"); } else if (prop.Name.Equals("Age")) { prop.SetValue(pObject, 25); } //else if (prop.Name.Equals("Age")) //{ // prop.SetValue(pObject, 25); //} } //SetValue:设置值 //GetValue:获取值 type.GetProperties();//属性 type.GetFields();//字段 foreach (var prop in type.GetProperties()) { Console.WriteLine($"people.{prop.Name}={prop.GetValue(pObject)}"); //if (prop.Name.Equals("Id")) //{ // prop.GetValue(pObject); //} //else if (prop.Name.Equals("Name")) //{ // prop.GetValue(pObject); //} //else if (prop.Name.Equals("Age")) //{ // prop.GetValue(pObject); // } } }Emit技术:在运行时去动态的生成Dll、Exe包括dll内部的方法、属性、字段...
public class ReflectionEmit { public static void Show() { // AssemblyBuilder// 建造者模式---创建Assembly //AssemblyName assemblyName = new AssemblyName("DynamicAssemblyExample"); AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("DynamicAssemblyExample"), AssemblyBuilderAccess.RunAndCollect); // 对于单个模块程序集,模块名称通常为;程序集名称加上扩展名。 ModuleBuilder modulebuilder = assemblyBuilder.DefineDynamicModule("MyModal"); //托管模块 TypeBuilder typebuilder = modulebuilder.DefineType("MyDynamicType", TypeAttributes.Public); //Type type= typebuilder.CreateType(); // 在Type中生成私有字段 FieldBuilder fieldBuilder = typebuilder.DefineField("NumberField", typeof(int), FieldAttributes.Public); // 定义一个接受整数参数的构造函数,储存在私人区域。 Type[] parameterTypes = { typeof(int) }; ConstructorBuilder ctor1 = typebuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, parameterTypes); //中间语言的生成者 ILGenerator ctor1IL = ctor1.GetILGenerator(); //对于构造函数,参数0是对新 //实例。在调用base之前将其推到堆栈上 //类构造函数。指定的默认构造函数 //通过传递 //类型(Type.EmptyTypes)到GetConstructor。 ctor1IL.Emit(OpCodes.Ldarg_0); ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); //在推送参数之前,先将实例推送到堆栈上 //将被分配给私有字段m\u编号。 ctor1IL.Emit(OpCodes.Ldarg_0); ctor1IL.Emit(OpCodes.Ldarg_1); ctor1IL.Emit(OpCodes.Stfld, fieldBuilder); ctor1IL.Emit(OpCodes.Ret); //完成构造函数传值, Int 设置给字段--测试代码 { //MyDynamicType myDynamicType = new MyDynamicType(123456); //int number = myDynamicType.NumberField; //// 动态的生成程序集; //// 动态的生成类; //// 动态的生成字段; //// 动态的生成构造函数; //Type type1 = typebuilder.CreateType(); //object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 }); //FieldInfo fieldInfo = type1.GetField("NumberField"); //object numberFieldResult = fieldInfo.GetValue(oInstacne); } MethodBuilder consoleMethod = typebuilder.DefineMethod("ConsoleMethod", MethodAttributes.Public | MethodAttributes.Static, null, null); ILGenerator consoleMethodIL = consoleMethod.GetILGenerator(); consoleMethodIL.Emit(OpCodes.Ldstr, "欢迎来到高级班第15期进阶学习"); consoleMethodIL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); consoleMethodIL.Emit(OpCodes.Ret); //写IL最后一定要Ret { Console.WriteLine("测试。。。。。。"); Type type1 = typebuilder.CreateType(); object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 }); MethodInfo myMethod = type1.GetMethod("ConsoleMethod"); object oResult = myMethod.Invoke(oInstacne, null); } MethodBuilder AddMethod = typebuilder.DefineMethod("AddMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(int), typeof(int) }); ILGenerator AddMethodIL = AddMethod.GetILGenerator(); AddMethodIL.Emit(OpCodes.Ldarg_0); AddMethodIL.Emit(OpCodes.Ldarg_1); AddMethodIL.Emit(OpCodes.Add_Ovf_Un); AddMethodIL.Emit(OpCodes.Ret); { //Console.WriteLine("测试。。。。。。"); //Type type1 = typebuilder.CreateType(); //object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 }); //MethodInfo myMethod = type1.GetMethod("AddMethod"); //object oResult = myMethod.Invoke(oInstacne, new object[] { 12, 34 }); } } }
关键知识点
- 先明确这个主题影响的是语法层、运行时层,还是性能与可维护性层。
- 学习时要同时关注语言表面写法和编译器、JIT、GC 等底层行为。
- 真正有价值的是知道“为什么这样写”和“在什么边界下不能这样写”。
项目落地视角
- 把示例改成最小可运行样例,并观察编译输出、运行结果和异常行为。
- 如果它会进入团队代码规范,最好同步补充命名约定、禁用场景和替代方案。
- 涉及性能结论时,优先用 Benchmark 或实际热点链路验证,而不是凭感觉判断。
常见误区
- 只记语法糖,不知道底层成本。
- 把适用于小样例的写法直接搬到高并发或大对象场景里。
- 忽略框架版本、语言版本和运行时差异,导致结论失真。
进阶路线
- 继续向源码、IL、JIT 行为和 BCL 实现层深入。
- 把知识点和代码评审、性能诊断、面试复盘结合起来。
- 把同类主题做横向对比,例如值类型与引用类型、迭代器与 async 状态机、反射与 Source Generator。
适用场景
- 当你准备把《反射》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合在需要理解语言特性、运行时行为或 API 边界时阅读。
- 当代码开始出现性能瓶颈、可维护性问题或语义歧义时,这类主题会直接影响实现质量。
落地建议
- 先写最小可运行样例,再把结论迁移到真实业务代码。
- 同时记录这个特性的收益、限制和替代方案,避免为了“高级”而使用。
- 涉及内存、并发或序列化时,最好配合调试器或基准测试验证。
排错清单
- 先确认问题属于编译期、运行期还是语义误用。
- 检查是否存在隐式转换、装箱拆箱、闭包捕获或上下文切换等隐藏成本。
- 查看异常栈、日志和最小复现代码,优先排除使用姿势问题。
复盘问题
- 如果把《反射》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《反射》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《反射》最大的收益和代价分别是什么?
反射性能优化
使用表达式树替代反射
/// <summary>
/// 使用表达式树缓存反射结果,大幅提升性能
/// 对比:原生反射 vs 表达式树缓存 vs 直接调用
/// </summary>
public static class FastReflection
{
// 1. 缓存构造函数 — 快速创建对象
private static readonly ConcurrentDictionary<Type, Func<object>> _constructorCache = new();
public static object FastCreateInstance(Type type)
{
var factory = _constructorCache.GetOrAdd(type, t =>
{
var newExpr = Expression.New(t);
var lambda = Expression.Lambda<Func<object>>(Expression.Convert(newExpr, typeof(object)));
return lambda.Compile();
});
return factory();
}
// 2. 缓存属性获取器 — 快速获取属性值
private static readonly ConcurrentDictionary<(Type, string), Func<object, object>> _getterCache = new();
public static object FastGetPropertyValue(object obj, string propertyName)
{
var type = obj.GetType();
var key = (type, propertyName);
var getter = _getterCache.GetOrAdd(key, k =>
{
var param = Expression.Parameter(typeof(object), "obj");
var cast = Expression.Convert(param, k.Item1);
var property = Expression.Property(cast, k.Item2);
var convert = Expression.Convert(property, typeof(object));
var lambda = Expression.Lambda<Func<object, object>>(convert, param);
return lambda.Compile();
});
return getter(obj);
}
// 3. 缓存属性设置器 — 快速设置属性值
private static readonly ConcurrentDictionary<(Type, string), Action<object, object>> _setterCache = new();
public static void FastSetPropertyValue(object obj, string propertyName, object value)
{
var type = obj.GetType();
var key = (type, propertyName);
var setter = _setterCache.GetOrAdd(key, k =>
{
var param = Expression.Parameter(typeof(object), "obj");
var valueParam = Expression.Parameter(typeof(object), "value");
var cast = Expression.Convert(param, k.Item1);
var property = Expression.Property(cast, k.Item2);
var castValue = Expression.Convert(valueParam, property.Type);
var assign = Expression.Assign(property, castValue);
var lambda = Expression.Lambda<Action<object, object>>(assign, param, valueParam);
return lambda.Compile();
});
setter(obj, value);
}
// 4. 缓存方法调用 — 快速调用方法
private static readonly ConcurrentDictionary<(Type, string), Func<object, object[], object>> _methodCache = new();
public static object FastInvokeMethod(object obj, string methodName, params object[] args)
{
var type = obj.GetType();
var key = (type, methodName);
var invoker = _methodCache.GetOrAdd(key, k =>
{
var param = Expression.Parameter(typeof(object), "obj");
var argsParam = Expression.Parameter(typeof(object[]), "args");
var cast = Expression.Convert(param, k.Item1);
var method = k.Item1.GetMethod(k.Item2);
if (method == null) throw new MissingMethodException(k.Item1.Name, k.Item2);
var parameters = method.GetParameters();
var argExpressions = new Expression[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var index = Expression.Constant(i);
var arrayAccess = Expression.ArrayIndex(argsParam, index);
argExpressions[i] = Expression.Convert(arrayAccess, parameters[i].ParameterType);
}
var call = Expression.Call(cast, method, argExpressions);
var convert = method.ReturnType == typeof(void)
? (Expression)Expression.Block(call, Expression.Constant(null))
: Expression.Convert(call, typeof(object));
var lambda = Expression.Lambda<Func<object, object[], object>>(convert, param, argsParam);
return lambda.Compile();
});
return invoker(obj, args);
}
}性能对比
/// <summary>
/// 反射性能对比测试
/// </summary>
public class ReflectionBenchmark
{
public static void Run()
{
const int iterations = 1_000_000;
var stopwatch = new Stopwatch();
// 1. 直接调用(基准)
stopwatch.Start();
for (int i = 0; i < iterations; i++)
{
var person = new People { Name = "Test", Age = 25 };
var name = person.Name;
}
stopwatch.Stop();
Console.WriteLine($"直接调用: {stopwatch.ElapsedMilliseconds}ms");
stopwatch.Reset();
// 2. 原生反射(每次都获取 PropertyInfo)
stopwatch.Start();
for (int i = 0; i < iterations; i++)
{
var person = new People { Name = "Test", Age = 25 };
var prop = typeof(People).GetProperty("Name");
var name = prop!.GetValue(person);
}
stopwatch.Stop();
Console.WriteLine($"原生反射: {stopwatch.ElapsedMilliseconds}ms");
stopwatch.Reset();
// 3. 缓存 PropertyInfo
var cachedProp = typeof(People).GetProperty("Name");
stopwatch.Start();
for (int i = 0; i < iterations; i++)
{
var person = new People { Name = "Test", Age = 25 };
var name = cachedProp!.GetValue(person);
}
stopwatch.Stop();
Console.WriteLine($"缓存反射: {stopwatch.ElapsedMilliseconds}ms");
stopwatch.Reset();
// 4. 表达式树缓存
stopwatch.Start();
for (int i = 0; i < iterations; i++)
{
var person = new People { Name = "Test", Age = 25 };
var name = FastReflection.FastGetPropertyValue(person, "Name");
}
stopwatch.Stop();
Console.WriteLine($"表达式树: {stopwatch.ElapsedMilliseconds}ms");
// 典型结果(100 万次调用):
// 直接调用: ~15ms
// 原生反射: ~6000ms(每次查找 PropertyInfo)
// 缓存反射: ~500ms(缓存 PropertyInfo,仍用 GetValue)
// 表达式树: ~40ms(接近直接调用的性能)
}
}反射在依赖注入中的应用
简易 IoC 容器
/// <summary>
/// 基于 反射 + 配置 的简易 IoC 容器
/// 演示反射在框架中的核心作用
/// </summary>
public class SimpleContainer
{
private readonly Dictionary<Type, Type> _registrations = new();
private readonly Dictionary<Type, object> _singletons = new();
private readonly object _lock = new();
// 注册接口到实现类
public void Register<TInterface, TImplementation>(bool singleton = false)
where TImplementation : TInterface
{
_registrations[typeof(TInterface)] = typeof(TImplementation);
}
// 解析实例
public TInterface Resolve<TInterface>()
{
return (TInterface)Resolve(typeof(TInterface));
}
private object Resolve(Type type)
{
if (_singletons.TryGetValue(type, out var singleton))
return singleton;
if (!_registrations.TryGetValue(type, out var implementationType))
throw new InvalidOperationException($"类型 {type.Name} 未注册");
// 使用反射查找构造函数
var constructor = implementationType.GetConstructors()
.OrderByDescending(c => c.GetParameters().Length)
.First();
// 递归解析构造函数参数
var parameters = constructor.GetParameters()
.Select(p => Resolve(p.ParameterType))
.ToArray();
// 使用反射创建实例
var instance = Activator.CreateInstance(implementationType, parameters)
?? throw new InvalidOperationException($"无法创建 {implementationType.Name}");
return instance;
}
// 从配置文件加载注册
public void LoadFromConfiguration(IConfiguration configuration)
{
var section = configuration.GetSection("IoC");
foreach (var item in section.GetChildren())
{
var interfaceType = Type.GetType(item["Interface"]!);
var implType = Type.GetType(item["Implementation"]!);
if (interfaceType != null && implType != null)
{
_registrations[interfaceType] = implType;
}
}
}
}
// appsettings.json 配置
// "IoC": [
// { "Interface": "MyApp.IRepository, MyApp", "Implementation": "MyApp.SqlRepository, MyApp" },
// { "Interface": "MyApp.IService, MyApp", "Implementation": "MyApp.UserService, MyApp" }
// ]反射的替代方案
Source Generator(编译时代码生成)
/// <summary>
/// .NET 5+ Source Generator 可以替代部分运行时反射场景
/// 编译时生成代码,零运行时开销
/// </summary>
// 传统反射方式(运行时)
// var prop = typeof(User).GetProperty("Name");
// prop.GetValue(user);
// Source Generator 方式(编译时生成)
// [GeneratedCode("MyGenerator", "1.0")]
// public static class UserPropertyAccessor
// {
// public static string GetName(User user) => user.Name;
// public static void SetName(User user, string value) => user.Name = value;
// }
// .NET 8 的 System.Text.Json 已使用 Source Generator
// [JsonSerializable(typeof(User))]
// public partial class UserContext : JsonSerializerContext { }
// 使用编译时生成的序列化代码(零反射)
// var json = JsonSerializer.Serialize(user, UserContext.Default.User);
// var user = JsonSerializer.Deserialize(json, UserContext.Default.User);