Feld Setter / Getter mit Delegate

c# delegates expression-trees field mono

Frage

Das ist mein einfacher Testcode. Ich möchte eine Feldzuweisungsverknüpfung zwischen zwei Objekten erstellen, und das Feld wird zur Laufzeit unter Verwendung von Reflexion durch Zwischenspeichern von Delegaten seiner Setzer / Getter-Methode bestimmt. Aber irgendwie funktioniert es nicht. Die Zuweisung funktioniert nicht. vielleicht habe ich einen dummen Fehler gemacht. Wo liege ich falsch?

public static class AssignmentExpression
{
    public static Expression Create(Expression left, Expression right)
    {
        MethodInfo m = typeof(AssignmentExpression)
                  .GetMethod("AssignTo", BindingFlags.NonPublic | BindingFlags.Static)
                  .MakeGenericMethod(left.Type);

        return Expression.Call( null,m,left, right);
    }

    private static void AssignTo<T>(ref T left, T right)  
    {                                                     
        left = right;                                     
    }
}

public class FieldLink
{
    protected Delegate srcGetter;
    protected Delegate dstSetter;

    public FieldLink(FieldInfo srcObject, FieldInfo dstObject)
    {
        this.srcGetter = FieldLink.createGetter(srcObject);
        this.dstSetter = FieldLink.createSetter(dstObject);
    }

    public void update<T>(T dst, T src)
    {
        this.dstSetter.DynamicInvoke(dst, this.srcGetter.DynamicInvoke(src));
    }

    protected static Delegate createGetter(FieldInfo field)
    {
        ParameterExpression objParm = Expression.Parameter(field.DeclaringType, "obj");
        Type delegateType = typeof(Func<,>).MakeGenericType(field.DeclaringType, field.FieldType);
        MemberExpression fieldExpr = Expression.Field(objParm, field.Name);
        LambdaExpression lambda = Expression.Lambda(delegateType, fieldExpr, objParm);
        return lambda.Compile();
    }

    protected static Delegate createSetter(FieldInfo field)
    {
        ParameterExpression objParm = Expression.Parameter(field.DeclaringType, "obj");
        ParameterExpression valueParm = Expression.Parameter(field.FieldType, "value");
        Type delegateType = typeof(Action<,>).MakeGenericType(field.DeclaringType, field.FieldType);
        MemberExpression memberExpr = Expression.Field(objParm, field.Name);
        Expression assignExpr = AssignmentExpression.Create(memberExpr, valueParm);
        LambdaExpression lambda = Expression.Lambda(delegateType, assignExpr, objParm, valueParm);
        return lambda.Compile();
    }
}

public class Test
{
    public int fieldInt = 0;
}

public class TestClass
{
    public Test a = new Test();
    public Test b = new Test();
    public void Start()
    {
        a.fieldInt = 5;

        Debug.Log("before a = " + a.fieldInt + " b = " + b.fieldInt);
        FieldLink testLink = new FieldLink(this.a.GetType().GetField("fieldInt"),
                                           this.b.GetType().GetField("fieldInt"));
        testLink.update(this.b, this.a);
        Debug.Log("after  a = " + a.fieldInt + " b = " + b.fieldInt);
        //here a.fieldInt should be equal to b.fieldInt, but somehow its unchanged!
    }
}

Akzeptierte Antwort

Dein Code scheint zu funktionieren, aber vielleicht nicht genau wie du es erwartest. Wenn Sie update aufrufen, übergeben Sie b.fieldInt als left Argument und a.fieldInt als right Argument. Die update weist dann dem Feld b.fieldInt den Wert a.fieldInt (5) zu, was dazu führt, dass beide Objekte einen fieldInt Wert von 5 haben. Wenn Sie die Argumente umkehren, enden beide Felder als Null. Erwartest du das nicht?

Nebenbei - und vielleicht haben Sie andere Gründe für die Verwendung Ihrer eigenen AssignmentExpression Klasse - aber Sie können tatsächlich ersetzen:

Expression assignExpr = AssignmentExpression.Create(memberExpr, valueParm);

...mit:

Expression assignExpr = Expression.Assign(memberExpr, valueParm);

... und du bekommst das gleiche Ergebnis.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum