Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing an unneeded boxing convert from a c# expression

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."

like image 305
Michiel Cornille Avatar asked Nov 17 '15 09:11

Michiel Cornille


1 Answers

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.

like image 114
LukeH Avatar answered Oct 24 '22 01:10

LukeH