我可以';t通过Expression.property访问对象的属性,除非馈送表达式的类型是强类型的

本文关键字:表达式 强类型 类型 属性 我可以 通过 Expression 对象 访问 property | 更新日期: 2023-09-27 18:27:16

我得到以下代码的异常:

public class InnerClass 
{
    public object Value { get; set; }
}
public class OuterClass
{
    // If I change the type of this property to "InnerClass" the exception is removed
    public object Inner { get; set; }
}
private static void SmallSandbox()
{
    var outer = new OuterClass()
    {
        Inner = new InnerClass()
        {
            Value = 2
        }
    };
    var p = Expression.Parameter(typeof(OuterClass), "p");
    Func<OuterClass, object> e = Expression.Lambda<Func<OuterClass, object>>(
        Expression.Property(Expression.Property(p, "Inner"), "Value"),
        p
    ).Compile();
    var a = new[] { outer }.Select(e).First();
    Console.WriteLine(a);
}

public object Inner { get; set; }更改为public InnerClass Inner { get; set; }将删除异常。这不是一个选项,因为我让程序的使用者最终提供属性名"Value"和相关对象——这是不可能提前知道的。

我可以做些什么来修复我的异常?

我可以';t通过Expression.property访问对象的属性,除非馈送表达式的类型是强类型的

Inner被声明为object。很明显,object不包含Value属性。在尝试访问该属性之前,您需要将该表达式"转换"为期望的类型。这相当于在表达式中添加强制转换。

Func<OuterClass, object> e = Expression.Lambda<Func<OuterClass, object>>(
    Expression.Property(
        Expression.Convert(Expression.Property(p, "Inner"), typeof(InnerClass)),
        "Value"
    ),
    p
).Compile();

这似乎有效。。。

        using Microsoft.CSharp.RuntimeBinder;

        var p = Expression.Parameter(typeof(OuterClass), "p");
        var binder = Binder.GetMember(CSharpBinderFlags.None, "Value", outer.Inner.GetType(), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
        var e = Expression.Lambda<Func<OuterClass, object>>(
            Expression.Dynamic(binder, typeof(object) ,Expression.Property(p, "Inner")),
            p
        ).Compile();