1

这是我的简单测试代码。我想在 2 个对象之间创建字段分配链接,并且该字段是在运行时通过缓存其 setter/getter 方法的委托使用反射确定的。但是,不知何故,它不起作用。任务不工作;也许我犯了一个愚蠢的错误。我哪里错了?

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

1 回答 1

1

您的代码似乎可以正常工作,但可能并不完全符合您的预期。当您调用时,update您将b.fieldInt作为left参数和参数a.fieldInt传入right;然后,该update方法将a.fieldInt(5) 的值分配给该b.fieldInt字段,从而使两个对象的fieldInt值都为 5。如果反转参数,则两个字段最终都为零。这不是你所期望的吗?

顺便说一句-也许您有其他原因使用自己的AssignmentExpression课程-但您实际上可以替换:

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

...和:

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

...你会得到相同的结果。

于 2013-02-04T12:52:36.217 回答