c#如何使用反射去创建一个委托_C# 反射的委托创建器

本文探讨了如何利用反射和委托在C#中提高代码执行效率,重点介绍了DelegateBuilder类的设计与实现,该类能智能地构造方法、构造函数、属性和字段的委托。通过Expression Tree,DelegateBuilder简化了反射调用,支持多种调用场景,如静态方法、实例方法、泛型方法等。此外,文章还讨论了何时使用委托代替反射以及效率问题,提供了一些基准测试示例。
摘要由CSDN通过智能技术生成

.Net 的反射是个很好很强大的东西,不过它的效率却实在是不给力。已经有很多人针对这个问题讨论过了,包括各种各样的 DynamicMethod 和各种各样的效率测试,不过总的来说解决方案就是利用 Expression Tree、Delegate.CreateDelegate 或者 Emit 构造出反射操作对应的委托,从而实现加速反射的目的。

虽然本篇文章同样是讨论利用委托来加速反射调用函数,不过重点并不在于如何提升调用速度,而是如何更加智能的构造出反射的委托,并最终完成一个方便易用的委托创建器 DelegateBuilder。

它的设计目标是:

能够对方法调用、构造函数调用,获取或设置属性和获取或设置字段提供支持。

能够构造出特定的委托类型,而不仅限于 Func 或者其它的 Func 和 Action,因为我个人很喜欢强类型的委托,同时类似 void MyDeleagte(params int[] args) 这样的委托有时候也是很有必要的,如果需要支持 ref 和 out 参数,就必须使用自定义的委托类型了。

能够支持泛型方法,因为利用反射选择泛型方法是件很纠结的事(除非没有同名方法),而且还需要再 MakeGenericMethod。

能够支持类型的显式转换,在对某些 private 类的实例方法构造委托时,实例本身就必须使用 object 传入才可以。

其中的 3、4 点,在前几篇随笔《C# 判断类型间能否隐式或强制类型转换》和《C# 泛型方法的类型推断》中已经被解决了,并且整合到了 PowerBinder 中,这里只要解决 1、2 点就可以了,这篇随笔就是来讨论如何根据反射来构造出相应的委托。

就目前完成的效果,DelegateBuilder 可以使用起来还是非常方便的,下面给出一些示例:

class Program {

public delegate void MyDelegate(params int[] args);

public static void TestMethod(int value) { }

public void TestMethod(uint value) { }

public static void TestMethod(params T[] arg) { }

static void Main(string[] args) {

Type type = typeof(Program);

Action m1 = type.CreateDelegate>("TestMethod");

m1(10);

Program p = new Program();

Action m2 = type.CreateDelegate>("TestMethod");

m2(p, 10);

Action m3 = type.CreateDelegate>("TestMethod");

m3(p, 10);

Action m4 = type.CreateDelegate>("TestMethod", p);

m4(10);

MyDelegate m5 = type.CreateDelegate("TestMethod");

m5(0, 1, 2);

}

}

可以说效果还是不错的,这里的 CreateDelegate 的用法与 Delegate.CreateDelegate 完全相同,功能却大大丰富,几乎可以只依靠 delegate type、type 和 memberName 构造出任何需要的委托,省去了自己反射获取类型成员的过程。

这里特别要强调一点:这个类用起来很简单,但是简单的背后是实现的复杂,所以各种没有发现的 bug 和推断错误是很正常的。

我再补充一点:虽然在这里我并不打算讨论效率问题,但的确有不少朋友对效率问题有点纠结,我就来详细解释下这个问题。

第一个问题:为什么要用委托来代替反射。如果手头有 Reflector 之类的反编译软件,可以看看 System.Reflection.RuntimeMethodInfo.Invoke 方法的实现,它首先需要检查参数(检查默认参数、类型转换之类的),然后检查各种 Flags,然后再调用 UnsafeInvokeInternal 完成真正的调用过程,显然比直接调用方法要慢上不少。而如果利用 Expression Tree 之类的方法构造出了委托,它就相当于只多了一层方法调用,性能不会损失多少(据说如果 Emit 用得好还能更快),因此才需要利用委托来代替反射。

第二个问题:什么时候适合用委托来代替反射。现在假设有一家公园,它的门票是 1 元,它还有一种终身票,票价是 20 元。如果我只是想进去看看,很可能以后就不再去了,那么我直接花 1 元进去是最合适的。但如果我想天天去溜达溜达,那么花 20 元买个终身票一定更加合适。

相对应的,1 元的门票就是反射,20 元的终身票就是委托——如果某个方法我只是偶尔调用一下,那么直接用反射就好了,反正损失也不是很大;如果我需要经常调用,花点时间构造个委托出来则是更好的选择,虽然构造委托这个过程比较慢,但它受用终身的。

第三个问题:怎么测试委托和反射的效率。测试效率的前提就是假设某个方法是需要被经常调用的,否则压根没必要使用委托。那么,基本的结构如下所示:

Stopwatch sw = new Stopwatch();

Type type = typeof(Program);

sw.Start();

Action action = type.CreateDelegate>("TestMethod");

for (int i = 0; i < 10000; i++)

{

action(i);

}

sw.Stop();

Console.WriteLine("DelegateBuilder:{0} ms", sw.ElapsedM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值