2010-05-16 179 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