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

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

【问题讨论】:

    标签: linq expression-trees


    【解决方案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 函数,其中一个参数是被分配者的值。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-09-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多