2013-02-04 2 views
1

이것은 내 간단한 테스트 코드입니다. 2 개체 사이의 필드 할당 링크를 만들고 싶습니다. 필드는 런타임시 setter/getter 메서드의 대리자를 캐싱하여 리플렉션을 사용하여 결정됩니다. 하지만, 어떻게 든 작동하지 않습니다. 할당이 작동하지 않습니다. 어쩌면 나는 어리석은 실수를 저질렀을지도 모른다. 내가 어디가 잘못 됐어?대리인을 사용하는 Field 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! 
    } 
} 

답변

1

코드가 작동하는 것처럼 보일 수도 있지만 정확히 예상 한 것과 다를 수 있습니다. update으로 전화하면 b.fieldIntleft 인수로 전달되고 a.fieldIntright 인수로 전달됩니다. update 메서드는 b.fieldInt 필드에 a.fieldInt (5) 값을 할당하여 fieldInt 값이 5 인 개체를 모두 값 5에 할당합니다. 인수를 반대로하면 두 필드가 모두 0으로 끝납니다. 그게 네가 기대하는 것이 아닌가? 여담으로

- 어쩌면 당신이 당신의 자신의 AssignmentExpression 클래스를 사용하는 다른 이유가있다 -하지만 당신이 실제로 대체 할 수

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

을 ...와 ...

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

및 당신은 같은 결과를 얻습니다.

+0

이상하게도 내 경우 args를 되 돌린 후에도 값은 동일합니다. btw 내 환경은. 닷넷 3.5 그래서 나는'Expression.Assign'을 가지고 있지 않다. – uray

+0

Ahh, ok - 나는 4.5에서 그것을 실행했다 - 다시 3.5에서 그것을 점검 할 것이다 ... –

+0

... 그것은 여전히 ​​나를 위해 일한다. VS2012, .NET 3.5에서 실행중인 'AssignmentExpression' 클래스 - 둘 다 5로 끝나거나 둘 다 결국 0으로 끝납니다. 매우 이상합니다! –