简体   繁体   中英

How to prevent Convert in generated expression for type parameter is interface

Here is the example code:

    public interface A
    {
        int MyProperty { get; set; }
    }

    public class B : A
    {
        public int MyProperty { get; set; }
    }

    public class C<T> where T : A
    {
        public Expression<Func<T, bool>> Expression { get; } = a => a.MyProperty > 0;
    }

    class Program
    {
        static void Main(string[] args)
        {
            var cExpression = new C<B>();
            Console.WriteLine(cExpression.Expression.ToString());
        }
    }

The output of the expression: a => (Convert(a, A).MyProperty > 0)

And I decompiled the code above and I got below:

public class C<T> where T : A
{
    public Expression<Func<T, bool>> Expression { get; } = (T a) => ((A)a).MyProperty > 0;

}

As you can see, the compiler added a cast option ((A)a) to the expression, that is what I DO NOT want, so the question is how can I tell the compiler NOT to do that?

There is no way to "tell the compiler" not to do this, but you can construct the expression tree directly:

public class C<T> where T : A {
    private static readonly MethodInfo s_propGetter = typeof(A).GetProperty(nameof(A.MyProperty)).GetMethod;

    public Expression<Func<T, bool>> Expr { get; private set; }

    public C() {
        var param = Expression.Parameter(typeof(T), "a");
        Expr = Expression.Lambda(
            typeof(Func<T, bool>),
            Expression.GreaterThan(Expression.Property(param, s_propGetter), Expression.Constant(0)),
            new[] {param}
        ) as Expression<Func<T, bool>>;
    }
}

Looks like the compiler is emitting the Convert because of the possibility of the generic type parameter to be struct (value type), even though the manual approach demonstrated by another answer proves that it is unnecessary.

But is is what it is. So the only way currently to tell compiler to not generate Convert (cast) is to put class constraint:

where T : class, A

Now the output of the original sample expression will be a => (a.MyProperty > 0)

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