12

割り当てを式ツリーにエンコードすることは可能ですか?

4

5 に答える 5

12

.NET4.0ライブラリでそれを行うことができるはずです。Microsoft.Scripting.Core.dllを.NET3.5プロジェクトにインポートします。

DLR 0.9を使用しています-バージョン1.0のExpession.BlockとExpression.Scopeに変更がある可能性があります(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();
        }
    }
}
于 2009-01-21T17:37:39.310 に答える
12

いいえ、そうは思いません。

確かに、C# コンパイラは、ラムダ式を変換するときにそれを許可しません。

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
于 2008-10-16T15:21:59.540 に答える
5

これを正確に行うための私の拡張方法:

/// <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
}
于 2010-11-09T08:21:51.447 に答える
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()

于 2010-10-19T20:16:21.647 に答える
2

おそらく、次の式ツリーで回避できます。引数が担当者の値であるラムダ関数を呼び出します。

于 2008-10-16T15:25:15.320 に答える