在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 | 基于反射的设置器 |