改进的“以非泛型方式调用泛型方法”之基于DynamicMethod的实现

本文针对双鱼座同志的 以非泛型方式调用泛型方法一文,提出一种更通用的以非泛型方式调用泛型方法的实现——基于DynamicMethod的实现。
基于DynamicMethod的实现的优点是,执行性能和双鱼座的文中实现的第5种方案——动态生成的非泛型接口包装相当(因为都是基于Emit的),但是,避免了原文实现中必须额外定义接口、Delegate的需要,从而,非常通用,应该是目前所能想到最佳实现。

首先,贴出原文中的测试数据相对于DynamicMethod实现的比较和缺点:

方案耗时比对其他优点
直接调用181不通用
泛型委托包装432.39不通用
反射16538918.78通用,不需额外定义
非泛型接口包装603.33通用,需要额外定义并实现
动态生成的非泛型接口包装724通用,需要额外定义
DynamicMethod实现724通用,无需额外定义

实现代码如下:

  1      public   abstract   class  DynamicMethodHelper
  2      {
  3        //该类不能实例化,只能静态调用
  4        private DynamicMethodHelper() {}
  5
  6        //通用的可变参数动态方法委托
  7        public delegate object DynamicMethodDelegate(params object[] paramObjs);
  8
  9        private static Dictionary<string, DynamicMethodDelegate> cache = new Dictionary<string, DynamicMethodDelegate>();
 10
 11        private static void LoadIndex(ILGenerator gen, int index)
 12        {
 13            switch (index)
 14            {
 15                case 0:
 16                    gen.Emit(OpCodes.Ldc_I4_0);
 17                    break;
 18                case 1:
 19                    gen.Emit(OpCodes.Ldc_I4_1);
 20                    break;
 21                case 2:
 22                    gen.Emit(OpCodes.Ldc_I4_2);
 23                    break;
 24                case 3:
 25                    gen.Emit(OpCodes.Ldc_I4_3);
 26                    break;
 27                case 4:
 28                    gen.Emit(OpCodes.Ldc_I4_4);
 29                    break;
 30                case 5:
 31                    gen.Emit(OpCodes.Ldc_I4_5);
 32                    break;
 33                case 6:
 34                    gen.Emit(OpCodes.Ldc_I4_6);
 35                    break;
 36                case 7:
 37                    gen.Emit(OpCodes.Ldc_I4_7);
 38                    break;
 39                case 8:
 40                    gen.Emit(OpCodes.Ldc_I4_8);
 41                    break;
 42                default:
 43                    if (index < 128)
 44                    {
 45                        gen.Emit(OpCodes.Ldc_I4_S, index);
 46                    }

 47                    else
 48                    {
 49                        gen.Emit(OpCodes.Ldc_I4, index);
 50                    }

 51                    break;
 52            }

 53        }

 54
 55        private static void StoreLocal(ILGenerator gen, int index)
 56        {
 57            switch (index)
 58            {
 59                case 0:
 60                    gen.Emit(OpCodes.Stloc_0);
 61                    break;
 62                case 1:
 63                    gen.Emit(OpCodes.Stloc_1);
 64                    break;
 65                case 2:
 66                    gen.Emit(OpCodes.Stloc_2);
 67                    break;
 68                case 3:
 69                    gen.Emit(OpCodes.Stloc_3);
 70                    break;
 71                default:
 72                    if (index < 128)
 73                    {
 74                        gen.Emit(OpCodes.Stloc_S, index);
 75                    }

 76                    else
 77                    {
 78                        gen.Emit(OpCodes.Stloc, index);
 79                    }

 80                    break;
 81            }

 82        }

 83
 84        private static void LoadLocal(ILGenerator gen, int index)
 85        {
 86            switch (index)
 87            {
 88                case 0:
 89                    gen.Emit(OpCodes.Ldloc_0);
 90                    break;
 91                case 1:
 92                    gen.Emit(OpCodes.Ldloc_1);
 93                    break;
 94                case 2:
 95                    gen.Emit(OpCodes.Ldloc_2);
 96                    break;
 97                case 3:
 98                    gen.Emit(OpCodes.Ldloc_3);
 99                    break;
100                default:
101                    if (index < 128)
102                    {
103                        gen.Emit(OpCodes.Ldloc_S, index);
104                    }

105                    else
106                    {
107                        gen.Emit(OpCodes.Ldloc, index);
108                    }

109                    break;
110            }

111        }

112
113        public static DynamicMethodDelegate GetDynamicMethodDelegate(MethodInfo genericMethodInfo, 
114            params Type[] genericParameterTypes)
115        {
116            检查参数的有效性
139
140            构造用于缓存的key
152
153            DynamicMethodDelegate dmd;
154
155            lock (cache)
156            {
157                if (cache.ContainsKey(key))
158                {
159                    dmd = cache[key];
160                }

161                else
162                {
163                    //动态创建一个封装了泛型方法调用的非泛型方法,并返回绑定到他的DynamicMethodDelegate的实例
164                    //返回的动态方法的实现在编译期就是以显式方法调用泛型方法的,因此,最大程度上避免了反射的性能损失
165                    DynamicMethod dm = new DynamicMethod(Guid.NewGuid().ToString("N"), 
166                        typeof(object), 
167                        new Type[] typeof(object[]) }
168                        typeof(string).Module);
169
170                    ILGenerator il = dm.GetILGenerator();
171
172                    创建所有方法的参数的本地变量
193
194                    从paramObjs参数中解析所有参数值到本地变量中
213
214                    执行目标方法
235
236                    il.Emit(OpCodes.Ret);
237
238                    dmd = (DynamicMethodDelegate)dm.CreateDelegate(typeof(DynamicMethodDelegate));
239                    cache.Add(key, dmd);
240                }

241            }

242
243            return dmd;
244        }

245    }

测试代码如下(基于在双鱼座原文的代码格式):

 1             List < int >  list  =   new  List < int > ();
 2             System.Diagnostics.Stopwatch watch  =   new  System.Diagnostics.Stopwatch();
 3             watch.Reset();
 4             watch.Start();
 5              for  ( int  i  =   0 ; i  <  REPEAT_TIME; i ++ )
 6              {
 7                Program.Add<int>(i, list);
 8            }

 9             watch.Stop();
10              long  l1  =  watch.ElapsedMilliseconds;
11             watch.Reset();
12             MethodInfo mi  =   typeof (Program).GetMethod( " Add " );
13             DynamicMethodHelper.DynamicMethodDelegate dmd  =  DynamicMethodHelper.GetDynamicMethodDelegate(mi,  typeof ( int ));
14             watch.Start();
15              for  ( int  i  =   0 ; i  <  REPEAT_TIME; i ++ )
16              {
17                dmd(i, list);
18            }

19             watch.Stop();
20              long  l2  =  watch.ElapsedMilliseconds;
21             Console.WriteLine( " {0}/n{1} vs {2} " , list.Count, l1, l2);
22             Console.ReadLine();


下载测试源代码

<think>好的,用户想写一篇关于C#反射的详细博客教程。我需要先理解反射的基本概念,然后组织内容结构,确保涵盖重要知识点。首先,反射的定义是什么?根据引用[5],反射可以动态创建类实例,这和静态创建不同。需要解释动态和静态创建的区别。 接下来,引用[1]提到反射分为字段反射和方法反射,所以应该在博客中分点讨论这两类。还要包括反射的应用场景,比如动态类创建、方法调用等,引用[1]和引用[4]中的例子,比如调用方法,需要详细说明。 然后,反射的实现机制可能涉及元数据操作,引用[2]指出反射是操作metadata的类库,需要解释元数据的概念和反射如何访问它。代码示例部分,引用[4]提供了加载程序集、获取类调用方法的代码,这些应该作为实例演示,帮助读者理解。 性能方面,引用[3]提到反射比直接调用慢,在性能敏感代码中应减少使用或缓存结果,这部分需要作为注意事项强调。安全性和类安全也是重点,引用[3]提到类安全的问题,需提醒开发者注意。 最后,应用场景部分,引用[1]和引用[5]的动态实例创建和动态方法调用是核心,可以举例说明实际开发中的用途,如插件系统或ORM框架。需要确保内容结构清晰,先基础后进阶,配合代码示例和注意事项,帮助读者全面掌握反射。</think># C#反射机制深度解析与应用指南 ## 一、反射基础概念 反射(Reflection)是.NET框架提供的元数据操作机制,允许在运行时动态获取类信息、创建对象实例、调用方法及访问字段属性。与静态创建类实例(`类名 对象名 = new 类名()`)不同,反射实现了类操作的动态化[^5]。 核心类库包含: - `System.Reflection`:反射基础命名空间 - `System.Type`:类信息核心类 - `Assembly`:程序集操作类 ## 二、反射实现机制 ### 1. 元数据操作 反射通过读取程序集元数据实现动态操作,元数据包含类定义、方法签名、特性标注等信息。程序集加载示例: ```csharp Assembly assembly = Assembly.LoadFrom("MyReflecttion.dll"); Type type = assembly.GetType("MyReflecttion.ReflectionTest"); ``` ### 2. 动态类创建 动态创建类实例的两种方式: ```csharp object obj1 = Activator.CreateInstance(type); // 无参构造 object obj2 = Activator.CreateInstance(type, new object[] { "参数" }); // 带参构造 ``` ## 三、核心应用场景 ### 1. 字段反射 ```csharp FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (var field in fields) { Console.WriteLine($"字段名:{field.Name},类:{field.FieldType}"); } ``` ### 2. 方法反射 动态调用方法示例: ```csharp MethodInfo show5 = type.GetMethod("Show5"); show5.Invoke(null, new object[] { "String" }); // 静态方法调用 ``` ### 3. 方法处理 ```csharp MethodInfo genericMethod = type.GetMethod("GenericMethod"); MethodInfo concreteMethod = genericMethod.MakeGenericMethod(typeof(string)); concreteMethod.Invoke(obj, new object[] { "test" }); ``` ## 四、性能优化策略 1. **缓存机制**:对重复使用的`Type`对象进行缓存 2. **BindingFlags优化**:精确指定成员搜索范围 3. **避免频繁反射**:在循环体等高频场景改用委托调用 4. **预编译表达式**:使用`System.Linq.Expressions`生成动态方法 ## 五、安全注意事项 1. **类安全验证**:`Type.IsAssignableFrom()`验证类兼容性 2. **权限控制**:`ReflectionPermissionFlag.MemberAccess`权限管理 3. **异常处理**:规范处理`TargetInvocationException`等反射异常 ## 六、典应用场景 1. **插件系统开发**:动态加载DLL实现功能扩展 2. **ORM框架**:实现对象关系映射 3. **序列化工具**:动态解析对象结构 4. **DI容器**:依赖注入实现 ```mermaid graph TD A[反射应用] --> B[动态类创建] A --> C[元数据读取] A --> D[延迟绑定] B --> E[插件系统] C --> F[代码分析工具] D --> G[动态代理] ``` ## 七、高级技巧 1. **特性反射**:通过`Attribute.GetCustomAttribute()`读取自定义特性 2. **动态程序集**:使用`AssemblyBuilder`构建运行时程序集 3. **IL代码生成**:结合`DynamicMethod`实现高性能动态方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值