Как я могу сделать эту работу с глубокими свойствами - PullRequest
3 голосов
/ 16 мая 2010

Учитывая следующий код ...

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 для глубоких свойств и мелких?

Спасибо.

1 Ответ

2 голосов
/ 16 мая 2010

Вам нужно воспользоваться тем, что ваше выражение. Боди уже представляет свойство, которое вы хотите установить. Это означает, что вы можете использовать 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);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...