Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Modified version. This class is probably better than many other ones you can find around :-) This is because this version support direct properties (<code>p =&gt; p.B</code>) (as everyone else :-) ), nested properties (<code>p =&gt; p.B.C.D</code>), fields (both "terminal" and "in the middle", so in <code>p =&gt; p.B.C.D</code> both <code>B</code> and <code>D</code> could be fields) and "inner" casting of types (so <code>p =&gt; ((BType)p.B).C.D</code> and <code>p =&gt; (p.B as BType).C.D)</code>. The only thing that isn't supported is casting of the "terminal" element (so no <code>p =&gt; (object)p.B</code>). </p> <p>There are two "codepaths" in the generator: for simple Expressions (<code>p =&gt; p.B</code>) and for "nested" expressions. There are code variants for .NET 4.0 (that has the <code>Expression.Assign</code> expression type). From some benchmarks of mine the fastest delegates are: "simple" <code>Delegate.CreateDelegate</code> for properties, <code>Expression.Assign</code> for fields and "simple" <code>FieldSetter</code> for fields (this one is just a little slower than <code>Expression.Assign</code> for fields). So under .NET 4.0 you should take away all the code marked as 3.5.</p> <p>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 <a href="https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-expression-tree/321686#321686">How do I set a field value in an C# Expression tree?</a> and <a href="https://stackoverflow.com/questions/208969/assignment-in-net-3-5-expression-trees/3972359#3972359">Assignment in .NET 3.5 expression trees</a>.</p> <pre><code>public static class FluentTools { public static Action&lt;T, TValue&gt; GetterToSetter&lt;T, TValue&gt;(Expression&lt;Func&lt;T, TValue&gt;&gt; getter) { ParameterExpression parameter; Expression instance; MemberExpression propertyOrField; GetMemberExpression(getter, out parameter, out instance, out propertyOrField); // Very simple case: p =&gt; p.Property or p =&gt; 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&lt;T, TValue&gt;)Delegate.CreateDelegate(typeof(Action&lt;T, TValue&gt;), 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&lt;T, TValue&gt;(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&lt;Action&lt;T, TValue&gt;&gt;(expr, parameter, value).Compile(); } private static void GetMemberExpression&lt;T, U&gt;(Expression&lt;Func&lt;T, U&gt;&gt; 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&lt;T, TValue&gt; FieldSetter&lt;T, TValue&gt;(FieldInfo field) { DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(TValue) }, typeof(FluentTools)); ILGenerator cg = m.GetILGenerator(); // arg0.&lt;field&gt; = arg1 cg.Emit(OpCodes.Ldarg_0); cg.Emit(OpCodes.Ldarg_1); cg.Emit(OpCodes.Stfld, field); cg.Emit(OpCodes.Ret); return (Action&lt;T, TValue&gt;)m.CreateDelegate(typeof(Action&lt;T, TValue&gt;)); } // 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&lt;T&gt;(ref T left, T right) // note the 'ref', which is { // important when assigning left = right; // to value types! } #endregion } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload