如何使用 Expression.Bind / Expression.MemberBind 绑定嵌套成员?

How to bind nested members using Expression.Bind / Expression.MemberBind?

测试类

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();

嵌套 属性 时,在 expression.Compile() 处抛出 'x' 未定义错误。如何绑定嵌套的 属性 Bar.Baz?

上面代码中构建的表达式是x => new BindFoo() {BarBaz = x.Bar.Baz},这是我想要的,但我认为x.Bar.Baz没有被正确绑定。

问题与Bind和嵌套成员无关,而是动态创建的lambda表达式的参数。

参数按实例绑定,而不是按名称绑定。这里

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

或使用表达式 visitor 将 baz.Parameters[0] 替换为新参数。