2010-05-16 6 views
3

Vu le code ci-dessous ...Comment puis-je faire ce travail en profondeur tout

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; } 

} 

L'appel à DoLambdaStuff(foo, f => f.Name) fonctionne bien parce que je suis accès à une propriété peu profonde, mais l'appel à DoLambdaStuff(foo, f => f.Bar.Description) échoue - même si la création de la fonction getValue fonctionne très bien, la création du setValueExpression échoue parce que je tente d'accéder à une propriété profonde de l'objet.

Quelqu'un peut-il s'il vous plaît me aider à modifier ce que je puisse créer le setValueExpression pour des propriétés profondes ainsi que superficielle?

Merci.

Répondre

2

Vous devez profiter du fait que votre expression.Body représente déjà la propriété que vous souhaitez définir. Cela signifie que vous pouvez utiliser expression.Body comme le membre de gauche dans votre expression d'affectation:

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

Merci, cela semble être exactement ce que je cherchais. –