三种属性操作性能比较:PropertyInfo + Expression Tree + Delega“.NET技术”te.CreateDelegate

简介:   在《上篇》中,我比较了三种属性操作的性能:直接操作,单纯通过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,这些接口和类型定义如下:

 
   
public class Bar{ }
public interface IFoo
{
Bar Bar {
get ; set ; }
}
public class Foo1 : IFoo
{
public Bar Bar { get ; set ; }
}
public class Foo2 : IFoo
{
public Bar Bar { get ; set ; }
}
public class Foo3 : IFoo
{
public Bar Bar { get ; set ; }
}

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

 
 
public delegate Bar GetPropertyValue();
public delegate void SetPropertyValue(Bar bar);

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

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

 
 
public static Func < object , object > CreateGetPropertyValueFunc()
{
var property
= typeof (IFoo).GetProperty( " Bar " );
var target
= Expression.Parameter( typeof ( object ));
var castTarget
= Expression.Convert(target, typeof (IFoo));
var getPropertyValue
= Expression.Property(castTarget, property);
var castPropertyvalue
= Expression.Convert(getPropertyValue, typeof ( object ));
return Expression.Lambda < Func < object , object >> (castPropertyvalue , target).Compile();
}

  下面是CreateSetPropertyValueAction方法,返回一个Action<object.object>委托:

 
 
public static Action < object , object > CreateSetPropertyValueAction()
{
var property
= typeof (IFoo).GetProperty( " Bar " );
var target
= Expression.Parameter( typeof ( object ));
var propertyValue
= Expression.Parameter( typeof ( object ));
var castTarget
= Expression.Convert(target, typeof (IFoo));
var castPropertyValue
= Expression.Convert(propertyValue, property.PropertyType);
var setPropertyValue
= Expression.Call(castTarget, property.GetSetMethod(), castPropertyValue);
return Expression.Lambda < Action < object , object >> (setPropertyValue, target, propertyValue).Compile();
}

  三、编写属性赋值操作测试方法

  接下来我们编写程序测试三种不同的属性赋值操作分别具有怎样的性能,所有的测试代码定义在如下TestSetPropertyValue静态方法中。该方法参数表示进行属性赋值操作迭代的次数,每次迭代分别对Foo1、Foo2和Foo3三个对象的Bar属性进行赋值。最后打印出三种赋值操作分别的耗时,时间单位为毫秒。

 
 
public static void TestSetPropertyValue( int times)
{
var foo1
= new Foo1();
var foo2
= new Foo2();
var foo3
= new Foo3();
var bar
= new Bar();
var property
= typeof (IFoo).GetProperty( " Bar " );
var setAction
= CreateSetPropertyValueAction();
var setDelegate1
= CreateSetPropertyValueDelegate(foo1);
var setDelegate2
= CreateSetPropertyValueDelegate(foo2);
var setDelegate3
= CreateSetPropertyValueDelegate(foo3);

var stopwatch
= new Stopwatch();
stopwatch.Start();
for ( int i = 0 ; i < times; i ++ )
{
property.SetValue(foo1, bar,
null );
property.SetValue(foo2, bar,
null );
property.SetValue(foo3, bar,
null );
}
var duration1
= stopwatch.ElapsedMilliseconds;

stopwatch.Restart();
for ( int i = 0 ; i < times; i ++ )
{
setAction(foo1, bar);
setAction(foo2, bar);
setAction(foo3, bar);
}
var duration2
= stopwatch.ElapsedMilliseconds;

stopwatch.Restart();
for ( int i = 0 ; i < times; i ++ )
{
setDelegate1(bar);
setDelegate2(bar);
setDelegate3(bar);
}
var duration3
= stopwatch.ElapsedMilliseconds;
Console.WriteLine(
" {0, -15}{1,-15}{2,-15}{3,-15} " , times, duration1, duration2, duration3);
}

  四、编写属性取值操作测试方法

  属性取值操作的测试方法TestGetPropertyValue与TestSetPropertyValue结构一样。先实例化三个IFoo对象(类型分别分Foo1、Foo2和Foo3),并初始化了它们的Bar属性。然后按照三种不同的方式获取该属性值,并打印出它们各自的耗时。

 
 
public static void TestGetPropertyValue( int times)
{
var foo1
= new Foo1 { Bar = new Bar() };
var foo2
= new Foo2 { Bar = new Bar() };
var foo3
= new Foo3 { Bar = new Bar() };

var property
= typeof (IFoo).GetProperty( " Bar " );
var getFunc
= CreateGetPropertyValueFunc();
var getDelegate1
= CreateGetPropertyValueDelegate(foo1);
var getDelegate2
= CreateGetPropertyValueDelegate(foo2);
var getDelegate3
= CreateGetPropertyValueDelegate(foo3);

var stopwatch
= new Stopwatch();
stopwatch.Start();
for ( int i = 0 ; i < times; i ++ )
{
var bar1
= property.GetValue(foo1, null );
var bar2
= property.GetValue(foo2, null );
var bar3
= property.GetValue(foo3, null );
}
var duration1
= stopwatch.ElapsedMilliseconds;

stopwatch.Restart();
for ( int i = 0 ; i < times; i ++ )
{
var bar1
= getFunc(foo1);
var bar2
= getFunc(foo2);
var bar3
= getFunc(foo3);
}
var duration2
= stopwatch.ElapsedMilliseconds;

stopwatch.Restart();
for ( int i = 0 ; i < times; i ++ )
{
var bar1
= getDelegate1();
var bar2
= getDelegate2();
var bar3
= getDelegate3();
}
var duration3
= stopwatch.ElapsedMilliseconds;

Console.WriteLine(
" {0, -15}{1,-15}{2,-15}{3,-15} " , times, duration1, duration2, duration3);
}

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

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

 
 
static void Main()
{
Console.WriteLine(
" {0, -15}{1,-15}{2,-15}{3,-15} " , " Times " , " Reflection " , " Expression " , " Delegate " );
TestSetPropertyValue(
10000 );
TestSetPropertyValue(
100000 );
TestSetPropertyValue(
1000000 );

Console.WriteLine();

TestGetPropertyValue(
10000 );
TestGetPropertyValue(
100000 );
TestGetPropertyValue(
1000000 );
}

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

 
 
Times Reflection Expression Delegate
10000 109 2 0
100000 992 21 3
1000000 9872 210 37

10000 80 2 0
100000 800 23 2
1000000 8007 239 28

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

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

  我们不妨来试试看。现在我们修改CreateGetPropertyValueFunc和CreateSetPropertyValueAction这两个静态方法,让它们直接返回Func<IFoo,Bar>和Acti上海企业网站设计与制作on<IFoo, Bar>,并去掉Expression.Convert语句。两个方法现在的定义如下:

 
 
public static Func < IFoo, Bar > CreateGetPropertyValueFunc()
{
var property
= typeof (IFoo).GetProperty( " Bar " );
var target
= Expression.Parameter( typeof (IFoo));
var getPropertyValue
= Expression.Property(target, property);
return Expression.Lambda < Func < IFoo, Bar >> (getPropertyValue, target).Compile();
}
public static Action < IFoo, Bar > CreateSetPropertyValueAction()
{
var property
= typeof (IFoo).GetProperty( " Bar " );
var target
= Expression.Parameter( typeof 上海企业网站制作"color: #000000;">(IFoo));
var propertyValue
= Expression.Parameter( typeof (Bar));
var setPropertyValue
= Expression.Call(target, property.GetSetMethod(), propertyValue);
return Expression.Lambda < Action < IFoo, Bar >> (setPropertyValue, target, propertyValue).Compile();
}

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

 
 
Times Reflection Expression Delegate
10000 107 1 0
100000 982 15 3
1000000 9802 157 37

10000 79 1 0
100000 789 18 2
1000000 7901 178 28
目录
相关文章
|
3月前
|
人工智能 前端开发 Devops
.NET技术在现代开发中的作用:.NET技术的核心价值、在现代应用开发中的实际应用、以及面临的挑战与未来趋势。
.NET技术是软件开发领域的核心力量,本文从其核心价值、实际应用及未来挑战三方面进行探讨。它支持多种语言,提供强大的开发工具和丰富的类库,并具备跨平台能力。在现代应用开发中,.NET广泛应用于企业级系统、Web应用、移动应用、云服务和游戏开发等领域。面对性能优化、容器化、AI集成等挑战,.NET持续创新以适应不断发展变化的技术环境。
62 4
|
3月前
|
人工智能 开发框架 .NET
.NET技术的强大功能:.NET技术的基础特性、在现代开发中的应用、以及它如何助力未来的软件开发。
.NET技术是软件开发领域的核心支柱,以其强大功能、灵活性及安全性广受认可。本文分三部分解析:基础特性如多语言支持、统一运行时环境;现代应用如企业级与Web开发、移动应用、云服务及游戏开发;以及未来趋势如性能优化、容器化、AI集成等,展望.NET在不断变化的技术环境中持续发展与创新。
120 4
|
3月前
|
人工智能 物联网 开发者
.NET技术在现代软件开发中的应用愈发广泛和深入
.NET技术是软件开发的关键支柱,本文分为三部分探讨其创新应用:最新进展如.NET 5/6统一平台、性能提升、跨平台支持增强、云集成优化及开源社区贡献;应用场景涵盖微服务架构、物联网、AI/机器学习、游戏及移动应用开发;未来发展潜力在于持续性能优化、云原生支持、新兴技术集成、生态扩张及教育培训加强。.NET正以其强大适应性和创新潜力引领软件开发的新方向。
48 3
|
3月前
|
人工智能 开发框架 .NET
如何掌握.NET技术,引领开发前沿:.NET技术的核心能力、在现代开发中的应用实践、以及如何通过.NET技术实现持续创新。
.NET技术已成为软件开发不可或缺的部分,本文分三部分探讨:核心能力如多语言支持、统一运行时环境、丰富的类库及跨平台能力;现代开发实践包括企业级应用、Web与移动开发、云服务及游戏开发;并通过性能优化、容器化、AI集成等方面实现持续创新,使开发者站在技术前沿。
67 3
|
7天前
|
人工智能 开发框架 前端开发
C#/.NET/.NET Core技术前沿周刊 | 第 12 期(2024年11.01-11.10)
C#/.NET/.NET Core技术前沿周刊 | 第 12 期(2024年11.01-11.10)
|
6天前
|
人工智能 开发框架 安全
C#/.NET/.NET Core技术前沿周刊 | 第 13 期(2024年11.11-11.17)
C#/.NET/.NET Core技术前沿周刊 | 第 13 期(2024年11.11-11.17)
|
1月前
|
人工智能 开发框架 C#
C#/.NET/.NET Core技术前沿周刊 | 第 6 期(2024年9.16-9.22)
C#/.NET/.NET Core技术前沿周刊 | 第 6 期(2024年9.16-9.22)
|
1月前
|
人工智能 开发框架 Cloud Native
C#/.NET/.NET Core技术前沿周刊 | 第 9 期(2024年10.07-10.13)
C#/.NET/.NET Core技术前沿周刊 | 第 9 期(2024年10.07-10.13)
|
1月前
|
数据可视化 NoSQL C#
C#/.NET/.NET Core技术前沿周刊 | 第 8 期(2024年10.01-10.06)
C#/.NET/.NET Core技术前沿周刊 | 第 8 期(2024年10.01-10.06)
|
1月前
|
设计模式 开发框架 C#
C#/.NET/.NET Core技术前沿周刊 | 第 4 期(2024年9.1-9.8)
C#/.NET/.NET Core技术前沿周刊 | 第 4 期(2024年9.1-9.8)