表达式来; Func键< TModel的,串>>表达<动作< TModel>> "吸

编程入门 行业动态 更新时间:2024-10-26 22:29:25
本文介绍了表达式来; Func键< TModel的,串>>表达<动作< TModel>> "吸气剂"到“Setter”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我很喜欢表达,而且我想知道如何以任何方式转换我的表达式

我们在这个例子中说我的TModel是Customer类型,并分配给这样的位置:

表达式< Func< TModel,string>> getvalueexpression = customer => customer.Name

表达式< Action< TModel,string>> setvalueexpression = [PSEUDOCODE] getvalueexpression = input Action< TModel,string> Setter = setvalueexpression.Compile(); Setter(mycustomer,value);

所以简而言之,我想以某种方式构建和编译一个表达式,设置由我指定的客户名称getter表达式,到一个特定的值。

解决方案

修改版本。这个类可能比许多其他你可以找到的更好:-)这是因为这个版本支持直接属性( p => pB )(和其他人一样 - )),嵌套属性( p => pBCD ),字段(两个终端和中间,所以在 p => ; pBCD B 和 D 可以是字段)和类型的内部 (所以 p =>((BType)pB).CD 和 p =>(pB为BType).CD)。唯一不支持的是终端元素的转换(所以没有 p =>(object)p.B )。

生成器中有两个codepath:对于简单表达式( 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< T,TValue> GetterToSetter< T,TValue>(表达式< Func< T,TValue> getter) { ParameterExpression参数; 表达式实例; MemberExpression propertyOrField; GetMemberExpression(getter,out参数,out instance,out propertyOrField); //很简单的情况:p => p.Property或p => p.Field if(parameter == instance) { if(propertyOrField.MemberType == MemberTypes.Property) { //这是更快比表达树! (在我的基准测试上为5x),但仅适用于属性 PropertyInfo property = propertyOrField.Member as PropertyInfo; MethodInfo setter = property.GetSetMethod(); var action =(Action< T,TValue>)Delegate.CreateDelegate(typeof(Action< T,TValue>),setter); 返回动作; } #region .NET 3.5 else // if(propertyOrField.MemberType == MemberTypes.Field) { // 1.2倍慢于4.0方法,比3.5方法快5倍 FieldInfo field = propertyOrField.Member as FieldInfo; var action = FieldSetter< T,TValue>(field); 返回动作; } #endregion } ParameterExpression value = Expression.Parameter(typeof(TValue),val); 表达式expr = null; #region .NET 3.5 if(propertyOrField.MemberType = MemberTypes.Property) { PropertyInfo property = propertyOrField.Member as PropertyInfo; MethodInfo setter = property.GetSetMethod(); expr = Expression.Call(instance,setter,value); } else // if(propertyOrField.MemberType == MemberTypes.Field) { expr = FieldSetter(propertyOrField,value); } #endregion //#区域.NET 4.0 ////对于现场访问,它比3.5方法快5倍,比简单 方法。对于物业访问速度几乎相同(1.1倍)。 // expr = Expression.Assign(propertyOrField,value); //#endregion return Expression.Lambda< Action< T,TValue>>(expr,parameter,value).Compile(); } private static void GetMemberExpression< T,U>(表达式< Func< T,U>>表达式,out ParameterExpression参数,out表达式实例,out MemberExpression propertyOrField) {表达式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 =当前为MemberExpression; current = propertyOrField.Expression; instance = current; while(current.NodeType!= ExpressionType.Parameter) { if(current.NodeType == ExpressionType.Convert || current.NodeType == ExpressionType.TypeAs) { current =(当前为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 //根据stackoverflow/questions/321650/how-do-i-set- a-field-value-in-a-c-expression-tree / 321686#321686 private static Action< T,TValue> FieldSetter< T,TValue>(FieldInfo字段) { DynamicMethod m = new DynamicMethod(setter,typeof(void),new Type [] {typeof(T),typeof(TValue)}, typeof运算(FluentTools)); ILGenerator cg = m.GetILGenerator(); // arg0。< field> = arg1 cg.Emit(OpCodes.Ldarg_0); cg.Emit(OpCodes.Ldarg_1); cg.Emit(OpCodes.Stfld,field); cg.Emit(OpCodes.Ret); return(Action< T,TValue>)m.CreateDelegate(typeof(Action< T,TValue>)); } //根据stackoverflow/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< T>(ref T left,T right)//注意'ref',这是 {//分配$ b时很重要$ b left = right; //到值类型! } #endregion }

I'm new to expressions, and i'd like to know how if it's in any way possible to convert my expression

Let's say in this example my TModel is of type Customer, and assigned it somewhere like this:

Expression<Func<TModel, string>> getvalueexpression = customer =>customer.Name

to something like

Expression<Action<TModel,string>> setvalueexpression = [PSEUDOCODE] getvalueexpression = input Action<TModel,string> Setter = setvalueexpression.Compile(); Setter(mycustomer,value);

So in short, i want to somehow build and compile an expression that sets the customer name specified by my getter expression, to a specific value.

解决方案

Modified version. This class is probably better than many other ones you can find around :-) This is because this version support direct properties (p => p.B) (as everyone else :-) ), nested properties (p => p.B.C.D), fields (both "terminal" and "in the middle", so in p => p.B.C.D both B and D could be fields) and "inner" casting of types (so p => ((BType)p.B).C.D and p => (p.B as BType).C.D). The only thing that isn't supported is casting of the "terminal" element (so no p => (object)p.B).

There are two "codepaths" in the generator: for simple Expressions (p => p.B) and for "nested" expressions. There are code variants for .NET 4.0 (that has the Expression.Assign expression type). From some benchmarks of mine the fastest delegates are: "simple" Delegate.CreateDelegate for properties, Expression.Assign for fields and "simple" FieldSetter for fields (this one is just a little slower than Expression.Assign for fields). So under .NET 4.0 you should take away all the code marked as 3.5.

Part of the code isn't mine. The initial (simple) version was based on the Fluent NHibernate code (but it supported only direct properties), some other parts are based on code from How do I set a field value in an C# Expression tree? and Assignment in .NET 3.5 expression trees.

public static class FluentTools { public static Action<T, TValue> GetterToSetter<T, TValue>(Expression<Func<T, TValue>> 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<T, TValue>)Delegate.CreateDelegate(typeof(Action<T, TValue>), 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<T, TValue>(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<Action<T, TValue>>(expr, parameter, value).Compile(); } private static void GetMemberExpression<T, U>(Expression<Func<T, U>> 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 stackoverflow/questions/321650/how-do-i-set-a-field-value-in-an-c-expression-tree/321686#321686 private static Action<T, TValue> FieldSetter<T, TValue>(FieldInfo field) { DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(TValue) }, typeof(FluentTools)); ILGenerator cg = m.GetILGenerator(); // arg0.<field> = arg1 cg.Emit(OpCodes.Ldarg_0); cg.Emit(OpCodes.Ldarg_1); cg.Emit(OpCodes.Stfld, field); cg.Emit(OpCodes.Ret); return (Action<T, TValue>)m.CreateDelegate(typeof(Action<T, TValue>)); } // Based on stackoverflow/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<T>(ref T left, T right) // note the 'ref', which is { // important when assigning left = right; // to value types! } #endregion }

更多推荐

表达式来; Func键&LT; TModel的,串&GT;&GT;表达&lt;动作&lt; TModel&gt;

本文发布于:2023-11-10 00:33:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1573869.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:表达式   动作   amp   LT   Func

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!