用表达式树读取对象的属性
我想为动态读取值的Object的每个属性创建一个Lambda表达式。
到目前为止我所拥有的:
var properties = typeof (TType).GetProperties().Where(p => p.CanRead); foreach (var propertyInfo in properties) { var getterMethodInfo = propertyInfo.GetGetMethod(); var entity = Expression.Parameter(typeof (TType)); var getterCall = Expression.Call(entity, getterMethodInfo); var lambda = Expression.Lambda(getterCall, entity); var expression = (Expression<Func>) lambda; var functionThatGetsValue = expression.Compile(); }
只要“TypeOfProperty”是硬编码的,当我调用functionThatGetsValue
时,代码运行良好。 我知道我无法动态传递“TypeOfPoperty”。 我能做些什么来实现我的目标?
假设您对Func
委托感到满意(根据上面的注释),您可以使用Expression.Convert
来实现:
var properties = typeof(TType).GetProperties().Where(p => p.CanRead); foreach (var propertyInfo in properties) { MethodInfo getterMethodInfo = propertyInfo.GetGetMethod(); ParameterExpression entity = Expression.Parameter(typeof(TType)); MethodCallExpression getterCall = Expression.Call(entity, getterMethodInfo); UnaryExpression castToObject = Expression.Convert(getterCall, typeof(object)); LambdaExpression lambda = Expression.Lambda(castToObject, entity); var functionThatGetsValue = (Func)lambda.Compile(); }
经过几个小时的谷歌搜索在这里找到答案。 我已经从博客文章中添加了片段,因为它可能会帮助其他人遇到同样的麻烦:
public static class PropertyInfoExtensions { public static Func GetValueGetter(this PropertyInfo propertyInfo) { if (typeof(T) != propertyInfo.DeclaringType) { throw new ArgumentException(); } var instance = Expression.Parameter(propertyInfo.DeclaringType, "i"); var property = Expression.Property(instance, propertyInfo); var convert = Expression.TypeAs(property, typeof(object)); return (Func)Expression.Lambda(convert, instance).Compile(); } public static Action GetValueSetter (this PropertyInfo propertyInfo) { if (typeof(T) != propertyInfo.DeclaringType) { throw new ArgumentException(); } var instance = Expression.Parameter(propertyInfo.DeclaringType, "i"); var argument = Expression.Parameter(typeof(object), "a"); var setterCall = Expression.Call( instance, propertyInfo.GetSetMethod(), Expression.Convert(argument, propertyInfo.PropertyType)); return (Action)Expression.Lambda(setterCall, instance, argument).Compile(); } }
我上面修改了gsharp的post,直接实际设置了值,使它更容易使用。 它并不理想,因为DynamicCastfunction的引入要求您事先了解您的类型。 我的目标是尽量保持强类型,不返回对象,避免使用动态关键字。 此外,将“魔法”保持在最低限度。
public static T DynamicCast(this object value) { return (T) value; } public static object GetPropertyValue (this PropertyInfo propertyInfo, T objectInstance) { if (typeof(T) != propertyInfo.DeclaringType) { throw new ArgumentException(); } var instance = Expression.Parameter(propertyInfo.DeclaringType, "i"); var property = Expression.Property(instance, propertyInfo); var convert = Expression.TypeAs(property, propertyInfo.PropertyType); var lambda = Expression.Lambda(convert, instance).Compile(); var result = lambda.DynamicInvoke(objectInstance); return result; } public static void SetPropertyValue(this PropertyInfo propertyInfo, T objectInstance, TP value) where T : class where TP : class { if (typeof(T) != propertyInfo.DeclaringType) { throw new ArgumentException(); } var instance = Expression.Parameter(propertyInfo.DeclaringType, "i"); var argument = Expression.Parameter(propertyInfo.PropertyType, "a"); var setterCall = Expression.Call( instance, propertyInfo.GetSetMethod(), Expression.Convert(argument, propertyInfo.PropertyType)); var lambda = Expression.Lambda(setterCall, instance, argument).Compile(); lambda.DynamicInvoke(objectInstance, value); }
例子:
public void Get_Value_Of_Property() { var testObject = new ReflectedType { AReferenceType_No_Attributes = new object(), Int32WithRange1_10 = 5, String_Requires = "Test String" }; var result = testObject.GetType().GetProperty("String_Requires").GetPropertyValue(testObject).DynamicCast(); result.Should().Be(testObject.String_Requires); } public void Set_Value_Of_Property() { var testObject = new ReflectedType { AReferenceType_No_Attributes = new object(), Int32WithRange1_10 = 5, String_Requires = "Test String" }; testObject.GetType().GetProperty("String_Requires").SetPropertyValue(testObject, "MAGIC"); testObject.String_Requires.Should().Be("MAGIC"); }
您可以编写一个使用MakeGenericMethod或表达式树的辅助方法,使lambda根据PropertyInfo对象执行类型化调用以调用DynamicCast,并避免必须事先知道它。 但那不那么优雅。
上述就是C#学习教程:用表达式树读取对象的属性分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/961504.html