2013-02-04 28 views
1

這是我的簡單測試代碼。我想在兩個對象之間創建字段分配鏈接,並且該字段在運行時使用通過緩存其setter/getter方法的委託來反映。但是,不知何故,它不起作用。作業不起作用;也許我犯了一個愚蠢的錯誤。我錯在哪裏?使用委託的字段設置器/ 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! 
    } 
} 

回答

1

您的代碼似乎正常工作,但可能並不完全符合您的期望。當您撥打update時,您通過b.fieldInt作爲left參數,a.fieldInt作爲right參數; update方法然後將a.fieldInt(5)的值分配給b.fieldInt字段,從而導致兩個對象的值爲5.如果反轉參數,則兩個字段均爲零。這不是你所期望的嗎?

順便說一句 - 也許你有其他原因使用自己的AssignmentExpression類 - 但實際上你可以替換:

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

...有:

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

...和你會得到同樣的結果。

+0

奇怪的是,在我的情況下,恢復參數後,值仍然是相同的。順便說一句,我的環境是。淨3.5,所以我沒有'Expression.Assign' – uray

+0

啊,好吧 - 我跑了4.5 - 我會再次檢查3.5 ... –

+0

...它仍然適用於我你在VS2012,.NET 3.5上運行的'AssignmentExpression'類都會以5結尾,或者兩者都以0結尾。非常奇怪! –