Removing an unneeded boxing convert from a c# expression
Asked Answered
S

1

10

I'm currently trying to convert an

Expression<Func<T,object>>

to an

Expression<Func<T,bool>> 

Currently the watch shows me that my expression holds

Expression<Func<T,object>> myExpression = model=>Convert(model.IsAnAirplane)

I'd like to simplify this to

Expression<Func<T,bool>> myExpression = model=>model.IsAnAirplane

Currently I only succeed at adding a convert, resulting in:

Expression<Func<T,bool>> myExpression = model=>Convert(Convert(model.IsAnAirplane))

But since the underlying type IS a bool, I should be able to scratch the converts entirely, right? I'm familiar with expression visitors etc, but still can't figure out how to remove the convert.

Edit: this accepted answer to this question Generic unboxing of Expression<Func<T, object>> to Expression<Func<T, TResult>> (that could be a possible duplicate) doesn't work for me ... as the expression gets translated by EF, you can see it does Convert(Convert()) instead of just removing the first convert... , this results in "Unable to cast the type 'System.Boolean' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types."

Saprogenic answered 17/11, 2015 at 9:38 Comment(0)
M
10

You should be able to strip out any Convert wrappers using something like this:

Expression<Func<YourModel, object>> boxed = m => m.IsAnAirplane;

var unboxed = (Expression<Func<YourModel, bool>>)StripConvert(boxed);

// ...

public static LambdaExpression StripConvert<T>(Expression<Func<T, object>> source)
{
    Expression result = source.Body;
    // use a loop in case there are nested Convert expressions for some crazy reason
    while (((result.NodeType == ExpressionType.Convert)
               || (result.NodeType == ExpressionType.ConvertChecked))
           && (result.Type == typeof(object)))
    {
        result = ((UnaryExpression)result).Operand;
    }
    return Expression.Lambda(result, source.Parameters);
}

If you prefer, you could alter StripConvert to return Expression<Func<T,U>> instead of a plain LambdaExpression and perform the cast inside the method itself, but in that case you wouldn't be able to take advantage of type-inferencing for the method call.

Morning answered 17/11, 2015 at 17:56 Comment(2)
This does exactly what I wanted, and works like a charm, thanks!Saprogenic
Please provide a sample of how to get Expression<Func<T,U>>. (Expression<Func<T,T2>>) Expression.Lambda(result, source.Parameters);?Sigmatism

© 2022 - 2024 — McMap. All rights reserved.