简体   繁体   中英

I can't access property on my object via Expression.Property unless the type of the fed expression is strongly-typed

I get an exception for the following code:

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

Changing public object Inner { get; set; } public object Inner { get; set; } public object Inner { get; set; } to public InnerClass Inner { get; set; } public InnerClass Inner { get; set; } public InnerClass Inner { get; set; } removes the exception. This is not an option because I'm having the consumer of my program ultimately provide the property name "Value" and the associated object - It can't be known ahead.

What can I do to fix my exception?

Inner is declared as an object . And clearly, an object doesn't contain a Value property. You need to "convert" that expression to the expected type before you attempt to access that property. This is equivalent to adding a cast to the expression.

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

this seem to work...

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM