Comment définir une valeur de champ dans une arborescence d'expression C #?

c# expression-trees lambda

Question

Donné:

FieldInfo field = <some valid string field on type T>;
ParameterExpression targetExp = Expression.Parameter(typeof(T), "target");
ParameterExpression valueExp = Expression.Parameter(typeof(string), "value");

Comment compiler une expression lambda pour définir le champ du paramètre "target" sur "value"?

Réponse acceptée

.Net 4.0 : maintenant qu’il ya Expression.Assign , c’est facile à faire:

FieldInfo field = typeof(T).GetField("fieldName");
ParameterExpression targetExp = Expression.Parameter(typeof(T), "target");
ParameterExpression valueExp = Expression.Parameter(typeof(string), "value");

// Expression.Property can be used here as well
MemberExpression fieldExp = Expression.Field(targetExp, field);
BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp);

var setter = Expression.Lambda<Action<T, string>>
    (assignExp, targetExp, valueExp).Compile();

setter(subject, "new value");

.Net 3.5 : vous ne pouvez pas, vous devrez utiliser System.Reflection.Emit à la place:

class Program
{
    class MyObject
    {
        public int MyField;
    }

    static Action<T,TValue> MakeSetter<T,TValue>(FieldInfo field)
    {
        DynamicMethod m = new DynamicMethod(
            "setter", typeof(void), new Type[] { typeof(T), typeof(TValue) }, typeof(Program));
        ILGenerator cg = m.GetILGenerator();

        // arg0.<field> = arg1
        cg.Emit(OpCodes.Ldarg_0);
        cg.Emit(OpCodes.Ldarg_1);
        cg.Emit(OpCodes.Stfld, field);
        cg.Emit(OpCodes.Ret);

        return (Action<T,TValue>) m.CreateDelegate(typeof(Action<T,TValue>));
    }

    static void Main()
    {
        FieldInfo f = typeof(MyObject).GetField("MyField");

        Action<MyObject,int> setter = MakeSetter<MyObject,int>(f);

        var obj = new MyObject();
        obj.MyField = 10;

        setter(obj, 42);

        Console.WriteLine(obj.MyField);
        Console.ReadLine();
    }
}

Réponse d'expert

Comme nous l’avons déjà mentionné, la définition d’un champ est problématique. Dans la version 3.5, vous pouvez utiliser une seule méthode, telle qu'un ensemble de propriétés, mais uniquement indirectement. Cela devient beaucoup plus facile dans 4.0, comme discuté ici . Cependant, si vous avez réellement des propriétés (pas des champs), vous pouvez faire beaucoup simplement avec Delegate.CreateDelegate :

using System;
using System.Reflection;
public class Foo
{
    public int Bar { get; set; }
}
static class Program
{
    static void Main()
    {
        MethodInfo method = typeof(Foo).GetProperty("Bar").GetSetMethod();
        Action<Foo, int> setter = (Action<Foo, int>)
            Delegate.CreateDelegate(typeof(Action<Foo, int>), method);

        Foo foo = new Foo();
        setter(foo, 12);
        Console.WriteLine(foo.Bar);
    }
}


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi