2008-10-16 7 views

Odpowiedz

12

Nie, nie wierzę w to.

pewnością kompilator C# wykluczy go przy konwersji wyrażenia lambda:

int x; 
Expression<Func<int,int>> foo = (x=y); // Assign to x and return value 

To daje błąd:

CS0832: An expression tree may not contain an assignment operator 
2

Można prawdopodobnie obejść przez nexting wyrażenia drzew. Wywołaj funkcję lambda, gdzie argumentem jest wartość cesjonariusza.

11

Powinieneś zrobić to z biblioteką .NET 4.0. importując plik Microsoft.Scripting.Core.dll do projektu .NET 3.5.

Używam DLR 0.9 - nie mogą być pewne zmiany na Expession.Block i Expression.Scope w wersji 1.0 (Można zobaczyć referencję http://www.codeplex.com/dlr/Thread/View.aspx?ThreadId=43234)

Po próbka jest pokazać.

using System; 
using System.Collections.Generic; 
using Microsoft.Scripting.Ast; 
using Microsoft.Linq.Expressions; 
using System.Reflection; 

namespace dlr_sample 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Expression> statements = new List<Expression>(); 

      ParameterExpression x = Expression.Variable(typeof(int), "r"); 
      ParameterExpression y = Expression.Variable(typeof(int), "y"); 

      statements.Add(
       Expression.Assign(
        x, 
        Expression.Constant(1) 
       ) 
      ); 

      statements.Add(
       Expression.Assign(
        y, 
        x 
       ) 
      ); 

      MethodInfo cw = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }); 

      statements.Add(
       Expression.Call(
        cw, 
        y 
       ) 
      ); 

      LambdaExpression lambda = Expression.Lambda(Expression.Scope(Expression.Block(statements), x, y)); 

      lambda.Compile().DynamicInvoke(); 
      Console.ReadLine(); 
     } 
    } 
} 
4

Jak Jon Skeet i TraumaPony już powiedziałem, Expression.Assign nie jest dostępna przed .NET 4. Oto kolejny konkretny przykład, jak obejść ten brakujący bit:

public static class AssignmentExpression 
{ 
    public static Expression Create(Expression left, Expression right) 
    { 
     return 
      Expression.Call(
       null, 
       typeof(AssignmentExpression) 
        .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! 
    } 
} 

Następnie wystarczy zadzwonić AssignmentExpression.Create() w miejsce Expression.Assign().

5

Moja metoda rozszerzenie dla robi dokładnie to:

/// <summary> 
/// Provides extensions for converting lambda functions into assignment actions 
/// </summary> 
public static class ExpressionExtenstions 
{ 
    /// <summary> 
    /// Converts a field/property retrieve expression into a field/property assign expression 
    /// </summary> 
    /// <typeparam name="TInstance">The type of the instance.</typeparam> 
    /// <typeparam name="TProp">The type of the prop.</typeparam> 
    /// <param name="fieldGetter">The field getter.</param> 
    /// <returns></returns> 
    public static Expression<Action<TInstance, TProp>> ToFieldAssignExpression<TInstance, TProp> 
     (
     this Expression<Func<TInstance, TProp>> fieldGetter 
     ) 
    { 
     if (fieldGetter == null) 
      throw new ArgumentNullException("fieldGetter"); 

     if (fieldGetter.Parameters.Count != 1 || !(fieldGetter.Body is MemberExpression)) 
      throw new ArgumentException(
       @"Input expression must be a single parameter field getter, e.g. g => g._fieldToSet or function(g) g._fieldToSet"); 

     var parms = new[] 
         { 
          fieldGetter.Parameters[0], 
          Expression.Parameter(typeof (TProp), "value") 
         }; 

     Expression body = Expression.Call(AssignmentHelper<TProp>.MethodInfoSetValue, 
              new[] {fieldGetter.Body, parms[1]}); 

     return Expression.Lambda<Action<TInstance, TProp>>(body, parms); 
    } 


    public static Action<TInstance, TProp> ToFieldAssignment<TInstance, TProp> 
     (
     this Expression<Func<TInstance, TProp>> fieldGetter 
     ) 
    { 
     return fieldGetter.ToFieldAssignExpression().Compile(); 
    } 

    #region Nested type: AssignmentHelper 

    private class AssignmentHelper<T> 
    { 
     internal static readonly MethodInfo MethodInfoSetValue = 
      typeof (AssignmentHelper<T>).GetMethod("SetValue", BindingFlags.NonPublic | BindingFlags.Static); 

     private static void SetValue(ref T target, T value) 
     { 
      target = value; 
     } 
    } 

    #endregion 
} 
+0

I nie może wydawać się uzyskać to do pracy, czy jest rewizja lub blogu gdzieś? – Maslow

Powiązane problemy