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

Community
  • 1
  • 1
Michiel Cornille
  • 2,067
  • 1
  • 19
  • 42

1 Answers1

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.

LukeH
  • 263,068
  • 57
  • 365
  • 409