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

Вам необходимо воспользоваться тем фактом, что ваше выражение.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

Спасибо, это похоже на то, что я искал. –

Смежные вопросы