سؤال

هل من الممكن لترميز مهمة في شجرة التعبير؟

هل كانت مفيدة؟

المحلول

لا، لا أعتقد ذلك.

وبالتأكيد 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

نصائح أخرى

ويجب عليك قادرة على القيام بذلك مع NET 4.0 مكتبة. بواسطة Microsoft.Scripting.Core.dll الاستيراد للمشروع. NET 3.5 الخاص بك.

وأستخدمه DLR 0.9 - قد يكون هناك بعض التغيير على Expession.Block وExpression.Scope في الإصدار 1.0 (يمكنك أن ترى إشارة من <لأ href = "http://www.codeplex.com/dlr/Thread/ View.aspx؟ رقم الموضوع = 43234 "يختلط =" noreferrer "> 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();
        }
    }
}

ولي طريقة التمديد لتفعل بالضبط هذا:

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

وكما قال جون السكيت و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().

وربما يمكن أن تغلب عليه nexting أشجار التعبير. استدعاء دالة امدا، حيث حجة هي قيمة المحال إليه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top