2010-05-16 176 views
3

考虑下面的代码这项工作...我怎样才能让深性质

class Program { 

    static void Main(string[] args) { 

     Foo foo = new Foo { Bar = new Bar { Description= "Martin" }, Name = "Martin" }; 

     DoLambdaStuff(foo, f => f.Name); 
     DoLambdaStuff(foo, f => f.Bar.Description); 

    } 

    static void DoLambdaStuff<TObject, TValue>(TObject obj, Expression<Func<TObject, TValue>> expression) { 

     // Set up and test "getter"... 

     Func<TObject, TValue> getValue = expression.Compile(); 

     TValue stuff = getValue(obj); 

     // Set up and test "setter"... 

     ParameterExpression objectParameterExpression = Expression.Parameter(typeof(TObject)), valueParameterExpression = Expression.Parameter(typeof(TValue)); 
     Expression<Action<TObject, TValue>> setValueExpression = Expression.Lambda<Action<TObject, TValue>>(
      Expression.Block(
       Expression.Assign(Expression.Property(objectParameterExpression, ((MemberExpression)expression.Body).Member.Name), valueParameterExpression) 
      ), objectParameterExpression, valueParameterExpression 
     ); 
     Action<TObject, TValue> setValue = setValueExpression.Compile(); 


     setValue(obj, stuff); 

    } 

} 

class Foo { 

    public Bar Bar { get; set; } 
    public string Name { get; set; } 

} 

class Bar { 

    public string Description{ get; set; } 

} 

因为我访问浅属性DoLambdaStuff(foo, f => f.Name)调用工作正常,但调用DoLambdaStuff(foo, f => f.Bar.Description)失败 - 虽然创作的getValue函数工作正常,创建setValueExpression失败,因为我试图访问该对象的深层属性。

任何人都可以请帮我修改这个,这样我就可以创建setValueExpression深的属性以及浅?

谢谢。

回答

2

您需要充分利用您的expression.Body已经代表您想要设置的属性。这意味着您可以在您的分配表达式中使用expression.Body作为左手边:

public static void Main(string[] args) 
    { 
     Foo foo = new Foo { Bar = new Bar { Name = "Martin", Buzz = new Fiz() { Name = "Carl" }}, Name = "Martin" }; 

     DoLambdaStuff(foo, f => f.Bar.Name, "Dennis"); 
     DoLambdaStuff(foo, f => f.Bar.Buzz.Name, "Dennis"); 
     Console.WriteLine(foo.Bar.Name); 
     Console.WriteLine(foo.Bar.Buzz.Name); 

    } 
    static void DoLambdaStuff<TObject, TValue>(TObject obj, Expression<Func<TObject, TValue>> expression, TValue valueToSet) 
    { 
     // Getter. 
     Func<TObject, TValue> getter = expression.Compile(); 
     TValue stuff = getter(obj); 

     ParameterExpression pObj = expression.Parameters[0]; 
     ParameterExpression pValue = Expression.Parameter(typeof (TValue), "value"); 
     var setterBlock = Expression.Block(
      Expression.Assign(expression.Body, pValue) 
      ); 

     var setterExpression = Expression.Lambda<Action<TObject, TValue>>(setterBlock, pObj, pValue); 
     Action<TObject, TValue> setter = setterExpression.Compile(); 

     // Test 
     setter(obj,valueToSet); 
    } 
+0

谢谢,这似乎正是我所期待的。 – 2010-05-16 11:15:06