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

Posted

技术标签:

【中文标题】从 c# 表达式中删除不需要的装箱转换【英文标题】:Removing an unneeded boxing convert from a c# expression 【发布时间】:2016-02-18 14:53:57 【问题描述】:

我目前正在尝试转换

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

但由于底层类型是布尔型,我应该能够完全从头开始转换,对吧?我对表达式访问者等很熟悉,但仍然不知道如何删除转换。

编辑:这个问题的公认答案Generic unboxing of Expression<Func<T, object>> to Expression<Func<T, TResult>>(可能是重复的)对我不起作用......因为表达式被 EF 翻译,你可以看到它确实 Convert(Convert())而不是仅仅删除第一个转换...,这会导致“无法将类型 'System.Boolean' 转换为类型 'System.Object'。LINQ to Entities 仅支持转换 EDM 基元或枚举类型。”

【问题讨论】:

【参考方案1】:

您应该能够使用类似这样的方式剥离任何 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 以返回 Expression&lt;Func&lt;T,U&gt;&gt; 而不是普通的 LambdaExpression 并在方法本身内部执行强制转换,但在这种情况下,您将无法利用 type-方法调用的推理。

【讨论】:

这正是我想要的,而且效果很好,谢谢! 谢谢,这真的救了我的命

以上是关于从 c# 表达式中删除不需要的装箱转换的主要内容,如果未能解决你的问题,请参考以下文章

第一部分 类型转换装箱和拆箱

正则表达式替换 char 并在 .net C# 中转换为大写

使用 C# 从 IP 地址中删除前导零

正则表达式从 C# 中删除行注释

删除json字符串c#中的尾随空格

C#装箱和拆箱