C# 通过反射调用参数类型未知的委托方法如何实现
解决方案
方案1:使用 Delegate.DynamicInvoke(兼容性最优,适合低频调用)
这是最通用的方案,所有.NET版本都支持,不需要提前知道委托的具体类型,直接调用基类Delegate的DynamicInvoke方法传入参数即可:
var Class2Type = System.Reflection.Assembly.GetExecutingAssembly().GetType("Class2"); var TestMethodType = typeof(TestClass).GetMethod("TestMethod",new Type[] { Class2Type }); var del = TestMethodType.CreateDelegate(typeof(Action<,>).MakeGenericType(typeof(TestClass),Class2Type)); // 调用逻辑 object testInstance = new TestClass(); object paramInstance = Activator.CreateInstance(Class2Type); // 动态创建参数类型实例 del.DynamicInvoke(testInstance, paramInstance);
注意:该方法基于反射实现,调用时有额外性能开销,适合调用频率不高的场景。
方案2:使用Expression树编译强类型委托(性能最优,适合高频调用)
如果需要多次调用该方法,可以通过Expression树构建一次强类型调用包装,后续调用性能接近原生强转委托的水平:
var Class2Type = System.Reflection.Assembly.GetExecutingAssembly().GetType("Class2"); var TestMethodType = typeof(TestClass).GetMethod("TestMethod",new Type[] { Class2Type }); // 构建调用表达式 var instanceParam = Expression.Parameter(typeof(object), "testInstance"); var paramParam = Expression.Parameter(typeof(object), "param"); var callExpr = Expression.Call( Expression.Convert(instanceParam, typeof(TestClass)), TestMethodType, Expression.Convert(paramParam, Class2Type) ); // 编译成通用签名的强类型委托 var callable = Expression.Lambda<Action<object, object>>(callExpr, instanceParam, paramParam).Compile(); // 后续直接调用,性能接近原生 callable(new TestClass(), Activator.CreateInstance(Class2Type));
注意:Expression编译本身有一次性开销,适合需要重复调用同一方法的场景。
方案3:使用dynamic动态绑定(写法最简)
如果不想处理类型转换逻辑,可以直接将委托和参数都转换为dynamic类型,由运行时完成绑定:
var Class2Type = System.Reflection.Assembly.GetExecutingAssembly().GetType("Class2"); var TestMethodType = typeof(TestClass).GetMethod("TestMethod",new Type[] { Class2Type }); var del = TestMethodType.CreateDelegate(typeof(Action<,>).MakeGenericType(typeof(TestClass),Class2Type)); dynamic dynamicDel = del; dynamicDel(new TestClass(), (dynamic)Activator.CreateInstance(Class2Type));
注意:该方法依赖运行时动态绑定,出错时调试难度较高,性能介于前两种方案之间。
内容的提问来源于stack exchange,提问作者tsdyy
相关产品推荐
相关产品推荐

