从 C# 表达式中删除不需要的装箱转换

Removing an unneeded boxing convert from a c# expression

我目前正在尝试转换

Expression<Func<T,object>>

Expression<Func<T,bool>> 

目前手表显示我的表情成立

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

我想将其简化为

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

目前我只成功添加了一个转换,导致:

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

但是由于底层类型是一个 bool,我应该能够完全抓取转换,对吧?我熟悉表达式访问者等,但仍然不知道如何删除转换。

编辑:这个问题 Generic unboxing of Expression<Func<T, object>> to Expression<Func<T, TResult>> 的已接受答案(可能是重复的)对我不起作用...当表达式被 EF 翻译时,您可以看到它确实 Convert( Convert()) 而不是只删除第一个 convert... ,这导致 "Unable to cast the type 'System.Boolean' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types."

您应该能够使用类似这样的方法去除任何 Convert 包装器:

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

如果您愿意,可以将 StripConvert 更改为 return Expression<Func<T,U>> 而不是普通的 LambdaExpression 并在方法本身内部执行转换,但在那种情况下您将无法利用方法调用的类型推断。