.NET 3.5 表达式树中的赋值

Posted

技术标签:

【中文标题】.NET 3.5 表达式树中的赋值【英文标题】:Assignment in .NET 3.5 expression trees 【发布时间】:2008-10-16 15:12:05 【问题描述】:

是否可以将赋值编码为表达式树?

【问题讨论】:

【参考方案1】:

不,我不这么认为。

当然,C# 编译器在转换 lambda 表达式时不允许这样做:

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

这会产生错误:

CS0832: An expression tree may not contain an assignment operator

【讨论】:

【参考方案2】:

您应该能够使用 .NET 4.0 库来做到这一点。通过将 Microsoft.Scripting.Core.dll 导入您的 .NET 3.5 项目。

我使用的是 DLR 0.9 - Expession.Block 和 Expression.Scope 在 1.0 版中可能会有一些变化(您可以查看来自 http://www.codeplex.com/dlr/Thread/View.aspx?ThreadId=43234 的参考)

以下示例向您展示。

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();
        
    

【讨论】:

【参考方案3】:

我的扩展方法就是这样做的:

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

【讨论】:

我似乎无法让它工作,是否有修订版或博客文章?【参考方案4】:

正如 Jon Skeet 和 TraumaPony 已经说过的,Expression.Assign 在 .NET 4 之前不可用。下面是另一个如何解决这个缺失位的具体示例:

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!
    

然后只需调用AssignmentExpression.Create() 代替Expression.Assign()

【讨论】:

【参考方案5】:

您可能可以通过下一个表达式树来解决它。调用一个 lambda 函数,其中一个参数是被分配者的值。

【讨论】:

以上是关于.NET 3.5 表达式树中的赋值的主要内容,如果未能解决你的问题,请参考以下文章

具有在语法树中的节点上定义的层次结构的表达式模板

有没有办法在 lambda 表达式树中使用“动态”?

golang编译原理

在表达式树中使用可为空的类型

Roslyn 语法树中的各种语法节点及每个节点的含义

3.5运算符