Как связать вложенные элементы с помощью Expression.Bind / Expression.MemberBind? - PullRequest
0 голосов
/ 18 октября 2018

Тестовые классы

public class Foo
{
    public Bar Bar { get; set; }
}

public class Bar
{
    public string Baz { get; set;  }
}

public class BindFoo
{
    public string BarBaz { get; set; }
}

Фрагмент

Expression<Func<Foo, object>> baz = x => x.Bar.Baz;
var param = Expression.Parameter(typeof(Foo), "x");

var bindings = typeof(BindFoo)
                    .GetProperties()
                    .Select(x => Expression.Bind(x, (MemberExpression)baz.Body))
                    .OfType<MemberBinding>()
                    .ToArray();

                var expression = Expression.Lambda<Func<Foo, object>>(
                        Expression.MemberInit(
                            Expression.New(typeof(BindFoo).GetConstructor(Type.EmptyTypes)),
                            bindings),
                    param);

                var func = expression.Compile();

Выдает ошибку «x», не определенную в expression.Compile(), когда свойство вложено.Как связать вложенное свойство Bar.Baz?

Выражение, встроенное в приведенный выше код: x => new BindFoo() {BarBaz = x.Bar.Baz}, и это то, что я хочу, но я думаю, что x.Bar.Baz не был правильно связан.

1 Ответ

0 голосов
/ 19 октября 2018

Проблема не связана с Bind и вложенными членами, но параметром динамически создаваемого лямбда-выражения.

Параметры связываются по экземпляру, а не по имени.Здесь

Expression<Func<Foo, object>> baz = x => x.Bar.Baz;
var param = Expression.Parameter(typeof(Foo), "x");

вы определили новый параметр, но затем пытаетесь использовать baz.Body, который связан с его собственным параметром.

Решение состоит в том, чтобы использовать исходный параметр

Expression<Func<Foo, object>> baz = x => x.Bar.Baz;
var param = baz.Parameters[0];

или замените baz.Parameters[0] новым параметром, используя выражение visitor.

...