2008-10-16 8 views

Respuesta

12

No, no lo creo.

Ciertamente, el compilador de C# no permite que al convertir una expresión lambda:

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

Esto produce el error:

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

Probablemente se podría evitar por nexting árboles de expresión. Llame a una función lambda, donde un argumento es el valor del asignado.

11

Debería poder hacerlo con .NET 4.0 Library. mediante la importación de Microsoft.Scripting.Core.dll a su proyecto .NET 3.5.

estoy usando DLR 0,9 - Es posible que haya algún cambio en Expession.Block y Expression.Scope en la versión 1.0 (se puede ver la referencia de http://www.codeplex.com/dlr/Thread/View.aspx?ThreadId=43234)

siguiente ejemplo es para mostrarle.

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

Como Jon Skeet y TraumaPony ya han dicho, Expression.Assign no está disponible antes de .NET 4. Aquí hay otro ejemplo concreto de cómo trabajar alrededor de este bit que falta:

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! 
    } 
} 

A continuación, sólo tiene que llamar AssignmentExpression.Create() en lugar de Expression.Assign().

5

Mi método de extensión por hacer exactamente esto:

/// <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

Me parece que no puede conseguir que esto funcione, es que hay un puesto de revisión o el blog en alguna parte? – Maslow