动态属性访问:反射与表达式树的比较

C#编程中,经常需要在编译时不知道确切名称的情况下动态访问对象的属性。通常,使用System.Reflection API的PropertyInfo类来实现这一点。这个类提供了GetValue()和SetValue()方法,允许根据属性的名称提取或设置C#属性的值。然而,使用反射API动态访问属性相比于通过静态API访问要慢得多——在测试中,速度差异超过了60倍。

考虑使用LINQ的表达式树作为替代方案。表达式树的一个优点是它们可以以类似于静态编译的方式进行编译。在网上找到了一些关于表达式树获取器和设置器的示例,例如“使用表达式树获取属性获取器和设置器”和“创建属性设置器委托”。基于上述网址中描述的代码,构建了自己的小型基于表达式的获取器和设置器库:

public static Func GetPropGetter(string propertyName) { ParameterExpression paramExpression = Expression.Parameter(typeof(TObject), "value"); Expression propertyGetterExpression = Expression.Property(paramExpression, propertyName); Func result = Expression.Lambda>(propertyGetterExpression, paramExpression).Compile(); return result; } public static Action GetPropSetter(string propertyName) { ParameterExpression paramExpression = Expression.Parameter(typeof(TObject)); ParameterExpression paramExpression2 = Expression.Parameter(typeof(TProperty), propertyName); MemberExpression propertyGetterExpression = Expression.Property(paramExpression, propertyName); Action result = Expression.Lambda>( Expression.Assign(propertyGetterExpression, paramExpression2), paramExpression, paramExpression2).Compile(); return result; }

还进行了一些基准测试,比较了这些获取器和设置器与以下类型的性能:直接静态编译代码设置和获取属性、静态编译的lambda表达式、基于反射的属性获取和设置。以下是在100000000个不同对象上运行获取器和设置器的结果,这些对象具有字符串属性:

获取器

时间(秒) 获取器类型
0.4 直接静态编译
0.64 静态编译Lambda
2.0 编译的表达式基础获取器
36.5 基于反射的获取器

设置器

时间(秒) 设置器类型
0.7 直接静态编译
1.0 静态编译Lambda
2.4 编译的表达式基础设置器
50.6 基于反射的设置器
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485