Vra

Is dit moontlik om 'n opdrag te enkodeer in 'n uitdrukking boom?

Was dit nuttig?

Oplossing

Nee, ek glo nie so nie.

Sekerlik die C # samesteller verbied dit wanneer die omskakeling van 'n lambda uitdrukking:

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

Dit gee die fout:

CS0832: An expression tree may not contain an assignment operator

Ander wenke

Jy moet in staat wees om dit te doen met NET 4.0 Biblioteek. deur die invoer Microsoft.Scripting.Core.dll om jou NET 3.5 projek.

Ek gebruik DLR 0.9 - Daar is dalk 'n verandering op Expession.Block en Expression.Scope in weergawe 1.0 (Jy kan verwysing van http://www.codeplex.com/dlr/Thread/View.aspx?ThreadId=43234 )

Na aanleiding van monster is om jou te wys.

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

My uitbreiding metode om dit te doen presies dit:

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

As Jon kleiduiven en TraumaPony reeds gesê, Expression.Assign is nie beskikbaar voor NET 4. Hier is nog 'n konkrete voorbeeld van hoe om te werk om hierdie vermiste bietjie:

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

Toe eenvoudig AssignmentExpression.Create() noem in plaas van Expression.Assign().

Jy kan waarskynlik werk om dit deur nexting uitdrukking bome. Bel 'n lambda funksie, waar 'n argument is die waarde van die sessionaris.

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top