加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

三种属性操作性能比较:PropertyInfo + Expression Tree + Deleg

发布时间:2020-12-16 09:11:34 所属栏目:asp.Net 来源:网络整理
导读:在《上篇》中,我比较了三种属性操作的性能:直接操作,单纯通过PropertyInfo反射和IL Emit。本篇继续讨论这个话题,我们再引入另外两种额外的属性操作方式:Expression Tree(这和IL Emit基本一致)和通过Delegate的静态方法CreateDelegate创建相应的委托进

在《上篇》中,我比较了三种属性操作的性能:直接操作,单纯通过PropertyInfo反射和IL Emit。本篇继续讨论这个话题,我们再引入另外两种额外的属性操作方式:Expression Tree(这和IL Emit基本一致)和通过Delegate的静态方法CreateDelegate创建相应的委托进行属性的赋值和取值。[源代码从这里下载]

目录
一、定义测试相关的接口、类型和委托
二、通过Expression Tree的方式创建用于属性操作的委托
三、编写属性赋值操作测试方法
四、编写属性取值操作测试方法
五、执行测试程序,查看测试结果
六、如果在Expression Tree中避免类型转换呢?

一、定义测试相关的接口、类型和委托

我首先定义了一个Bar类型和IFoo接口,该接口中仅仅包含一个类型和名称为Bar的可读写属性。Foo1、Foo2和Foo3均实现接口IFoo,这些接口和类型定义如下:

   1: public class Bar{ }
   3: {
   5: }
   7: {
   9: }
  11: {
  14: class Foo3 : IFoo
  16:       17: }

然后定义如下两个委托:GetPropertyValue和SetPropertyValue。如它们的名称所表示的那些,它们分别表示属性取值和赋值操作:

delegate void SetPropertyValue(Bar bar);

二、通过Expression Tree的方式创建用于属性操作的委托

接下来我们编写Expression Tree的方式完成属性赋值和取值的操作,它们实现在如下两个静态方法中:CreateGetPropertyValueFunc和CreateSetPropertyValueAction。下面是CreateGetPropertyValueFunc的定义,它返回的是一个Func<object.object>委托:

2: {
   4:     var target              = Expression.Parameter(typeof(object));
   6:     var getPropertyValue    = Expression.Property(castTarget,property);
return Expression.Lambda<Func<object>>(castPropertyvalue,target).Compile();
static Action<object> CreateSetPropertyValueAction()
   7:     var castPropertyValue   = Expression.Convert(propertyValue,property.PropertyType);
   9:     return Expression.Lambda<Action<object>>(setPropertyValue,target,propertyValue).Compile();
static void TestSetPropertyValue(int times)
   4:     var foo2            = new Foo2();
   6:     var bar             = new Bar();
   9:     var setDelegate1    = CreateSetPropertyValueDelegate(foo1);
  11:     var setDelegate3    = CreateSetPropertyValueDelegate(foo3);
  13:     var stopwatch = new Stopwatch();
  15:     for (int i = 0; i < times; i++)
  17:         property.SetValue(foo1,bar,1)">null);
  19:         property.SetValue(foo3,1)" id="lnum20">  20:     }
  22:? 
  24:     int i = 0; i < times; i++)
  26:         setAction(foo1,bar);
  28:         setAction(foo3,1)" id="lnum29">  29:     }
  31:? 
  33:       34:     {
  36:         setDelegate2(bar);
  38:     }
  40:     Console.WriteLine("{0,-15}{1,-15}{2,-15}{3,-15}",times,duration1,duration2,duration3);
void TestGetPropertyValue(new Foo1 { Bar = new Bar() };
new Foo3 { Bar =    6:? 
   9:     var getDelegate1    = CreateGetPropertyValueDelegate(foo1);
  11:     var getDelegate3    = CreateGetPropertyValueDelegate(foo3);
  27:         var bar2 = getFunc(foo2);
  35:         var bar1 = getDelegate1();
  37:         var bar3 = getDelegate3();
  40:? 
  42: }

五、执行测试程序,查看测试结果

我们直接通过一个Console应用来测试,在Main()方法中编写了如下的测试程序。先三次调用TestSetPropertyValue方法测试属性赋值操作,传入表示迭代次数的参数分别为10000(一万)、100000(十万)和1000000(一百万)。然后按照相同的方式调用TestGetPropertyValue测试属性取值操作。

3: Console.WriteLine("Times",1)">"Reflection",1)">"Expression",1)">"Delegate");
   5:     TestSetPropertyValue(100000);
   7:? 
   9:? 
  11:     TestGetPropertyValue(100000);
  13: }

从下面的输出结果来看,不论是属性的赋值还是取值,单纯通过PropertyInfo的方式所耗用的时间都比其它两种形式要长的多。至于其它两种(Expression Tree和通过Delegate.CreateDelegate创建委托)来说,后者又比前者有明显的优势。

2: 10000 109 2 0
   4: 1000000        9872           210            37
   6: 10000          80             2              0
   8: 1000000        8007           239            28

六、如果在Expression Tree中避免类型转换呢?

当我们调用Delegate的静态方法CreateDelegate是,需要指定具体的委托类型。对于属性的操作来说,属性类型需要与指定的委托类型相匹配,所以这就避免了类型转化这个步骤。但是对于Expression Tree的属性操作来说,由于返回的类型是Func<object,object>和Action<object,object>,需要对目标对象和属性值进行两次类型转换。如果将类型转换这个步骤从Expression Tree中移掉,两者的性能是否一致呢?

我们不妨来试试看。现在我们修改CreateGetPropertyValueFunc和CreateSetPropertyValueAction这两个静态方法,让它们直接返回Func<IFoo,Bar>和Action<IFoo,Bar>,并去掉Expression.Convert语句。两个方法现在的定义如下:

5: var getPropertyValue = Expression.Property(target,property);
   8: static Action<IFoo,Bar> CreateSetPropertyValueAction()
  10:     var property            = "Bar");
  13:     var setPropertyValue    = Expression.Call(target,propertyValue);
  15: }

在这种情况下,再次运行我们的测试程序,你会得到如下的输出结果。从中我们不难看出,通过上面的修改,Expression Tree形式的操作在性能上得到了一定的提升,但是和第三种依然有一定的差距。

3: 100000 982 15 3
   6: 10000          79             1              0
   8: 1000000        7901           178            28

晚绑定场景下对象属性赋值和取值可以不需要PropertyInfo
三种属性操作性能比较:PropertyInfo + Expression Tree + Delegate.CreateDelegate
关于Expression Tree和IL Emit的所谓的"性能差别"

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读