表达式<Func >到Expression <Action >“Getter”到“Setter”
我是表达式的新手,我想知道如何以任何方式转换我的表达式
让我们说在这个例子中我的TModel是Customer类型,并将它分配到这样的地方:
Expression<Func> getvalueexpression = customer =>customer.Name
喜欢的东西
Expression<Action> setvalueexpression = [PSEUDOCODE] getvalueexpression = input Action Setter = setvalueexpression.Compile(); Setter(mycustomer,value);
所以简而言之,我想以某种方式构建和编译一个表达式,该表达式将我的getter表达式指定的客户名称设置为特定值。
修改版。 这个类可能比你可以找到的许多其他类更好:-)这是因为这个版本支持直接属性( p => pB
)(和其他人一样:-)),嵌套属性( p => pBCD
),字段( “终点”和“中间”,所以在p => pBCD
, B
和D
都可以是字段)和“内部”类型的转换(所以p => ((BType)pB).CD
和p => (pB as BType).CD)
。 唯一不支持的是铸造“终端”元素(所以没有p => (object)pB
)。
生成器中有两个“代码路径”:简单表达式( p => pB
)和“嵌套”表达式。 .NET 4.0有代码变体(具有Expression.Assign
表达式类型)。 从我的一些基准测试中,最快的代表是:“简单”的Delegate.CreateDelegate
用于属性, Expression.Assign
用于字段,“简单” FieldSetter
用于字段(这个字段比Expression.Assign
字段慢一点)。 因此,在.NET 4.0下,您应该删除标记为3.5的所有代码。
部分代码不是我的。 初始(简单)版本基于Fluent NHibernate代码(但它仅支持直接属性),其他一些部分基于如何在C#表达式树中设置字段值的代码? 和.NET 3.5表达式树中的赋值 。
public static class FluentTools { public static Action GetterToSetter(Expression> getter) { ParameterExpression parameter; Expression instance; MemberExpression propertyOrField; GetMemberExpression(getter, out parameter, out instance, out propertyOrField); // Very simple case: p => p.Property or p => p.Field if (parameter == instance) { if (propertyOrField.Member.MemberType == MemberTypes.Property) { // This is FASTER than Expression trees! (5x on my benchmarks) but works only on properties PropertyInfo property = propertyOrField.Member as PropertyInfo; MethodInfo setter = property.GetSetMethod(); var action = (Action)Delegate.CreateDelegate(typeof(Action), setter); return action; } #region .NET 3.5 else // if (propertyOrField.Member.MemberType == MemberTypes.Field) { // 1.2x slower than 4.0 method, 5x faster than 3.5 method FieldInfo field = propertyOrField.Member as FieldInfo; var action = FieldSetter(field); return action; } #endregion } ParameterExpression value = Expression.Parameter(typeof(TValue), "val"); Expression expr = null; #region .NET 3.5 if (propertyOrField.Member.MemberType == MemberTypes.Property) { PropertyInfo property = propertyOrField.Member as PropertyInfo; MethodInfo setter = property.GetSetMethod(); expr = Expression.Call(instance, setter, value); } else // if (propertyOrField.Member.MemberType == MemberTypes.Field) { expr = FieldSetter(propertyOrField, value); } #endregion //#region .NET 4.0 //// For field access it's 5x faster than the 3.5 method and 1.2x than "simple" method. For property access nearly same speed (1.1x faster). //expr = Expression.Assign(propertyOrField, value); //#endregion return Expression.Lambda>(expr, parameter, value).Compile(); } private static void GetMemberExpression(Expression> expression, out ParameterExpression parameter, out Expression instance, out MemberExpression propertyOrField) { Expression current = expression.Body; while (current.NodeType == ExpressionType.Convert || current.NodeType == ExpressionType.TypeAs) { current = (current as UnaryExpression).Operand; } if (current.NodeType != ExpressionType.MemberAccess) { throw new ArgumentException(); } propertyOrField = current as MemberExpression; current = propertyOrField.Expression; instance = current; while (current.NodeType != ExpressionType.Parameter) { if (current.NodeType == ExpressionType.Convert || current.NodeType == ExpressionType.TypeAs) { current = (current as UnaryExpression).Operand; } else if (current.NodeType == ExpressionType.MemberAccess) { current = (current as MemberExpression).Expression; } else { throw new ArgumentException(); } } parameter = current as ParameterExpression; } #region .NET 3.5 // Based on https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-expression-tree/321686#321686 private static Action FieldSetter(FieldInfo field) { DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(TValue) }, typeof(FluentTools)); ILGenerator cg = m.GetILGenerator(); // arg0. = arg1 cg.Emit(OpCodes.Ldarg_0); cg.Emit(OpCodes.Ldarg_1); cg.Emit(OpCodes.Stfld, field); cg.Emit(OpCodes.Ret); return (Action)m.CreateDelegate(typeof(Action)); } // Based on https://stackoverflow.com/questions/208969/assignment-in-net-3-5-expression-trees/3972359#3972359 private static Expression FieldSetter(Expression left, Expression right) { return Expression.Call( null, typeof(FluentTools) .GetMethod("AssignTo", BindingFlags.NonPublic | BindingFlags.Static) .MakeGenericMethod(left.Type), left, right); } private static void AssignTo(ref T left, T right) // note the 'ref', which is { // important when assigning left = right; // to value types! } #endregion }
static Expression> MakeSetter(Expression> getter) { var memberExpr = (MemberExpression)getter.Body; var @this = Expression.Parameter(typeof(T), "$this"); var value = Expression.Parameter(typeof(TProperty), "value"); return Expression.Lambda>( Expression.Assign(Expression.MakeMemberAccess(@this, memberExpr.Member), value), @this, value); }
我有这个帮助方法,它返回属性的属性信息:
public static PropertyInfo GetPropertyInfo(Expression> property) where T : class { var memberExpression = (property.Body as MemberExpression); if (memberExpression != null && memberExpression.Member is PropertyInfo) { return memberExpression.Member as PropertyInfo; } throw new InvalidOperationException("Invalid usage of GetPropertyInfo"); }
用法: GetPropertyInfo((MyClass c) => c.PropertyName);
然后,您可以使用PropertyInfo在类上设置属性的值。
您需要修改代码以满足您的需求,但希望它会有所帮助。
这是我的方式
public static Action GenerateSetterAction(PropertyInfo pi) { //p=> p.=(pi.PropertyType)v var expParamP = Expression.Parameter(typeof(T), "p"); var expParamV = Expression.Parameter(typeof(object), "v"); var expParamVc = Expression.Convert(expParamV, pi.PropertyType); var mma = Expression.Call( expParamP , pi.GetSetMethod() , expParamVc ); var exp = Expression.Lambda>(mma, expParamP, expParamV); return exp.Compile(); }
由于正确的答案对我不起作用(表达式中的集合)但是把我推向了正确的方向,我需要对此进行大量调查,我想我想出了一种方法,可以为字面上的任何成员表达式生成setter。
对于属性和字段,它的行为与标记的答案相同(我相信它更透明)。
它还有对列表和词典的额外支持 – 请参阅注释。
上述就是C#学习教程:表达式<Func >到Expression <Action >“Getter”到“Setter”分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
public static Action GetSetter(Expression> getterExpression) { /*** SIMPLE PROPERTIES AND FIELDS ***/ // check if the getter expression reffers directly to a PROPERTY or FIELD var memberAcessExpression = getterExpression.Body as MemberExpression; if (memberAcessExpression != null) { //to here we assign the SetValue method of a property or field Action
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1251169.html