用于比较两个枚举值的 Linq 表达式

Sha*_*ica 5 c# linq-to-entities

我正在我的应用程序中进行一些表达式构建,该应用程序大部分时间都在工作。但是当我尝试对枚举值进行比较运算时,我遇到了麻烦。例如:

expr = Expression.GreaterThanOrEqual(memberExpression, constExpression);
Run Code Online (Sandbox Code Playgroud)

memberExpression这在和constExpression都是类型之前都可以正常工作MyEnum;这会引发运行时错误:

没有为类型“MyNamespace.MyEnum”和“MyNamespace.MyEnum”定义二元运算符 GreaterThanOrEqual。

我可以通过将枚举值转换为整数来在其他地方绕过它,但这似乎是错误的。如果我可以在 C# 中的值之间进行比较运算MyEnum,那么为什么表达式生成器不允许这样做呢?

Jon*_*Jon 4

我可以通过将枚举值转换为整数来在其他地方绕过它,但这似乎是错误的。

感觉应该不会有错。毕竟,这就是编译器本身所做的事情——它要么用枚举值替换其相应的数值(当枚举值在编译时已知时),要么生成在运行时执行必要的转换的代码。请注意,这些强制转换不一定是int相关枚举的支持类型,而是相关枚举的支持类型。

如果我可以在 C# 中的值之间进行比较操作MyEnum,那么为什么Expression构建器不允许这样做呢?

您正在构建的表达式树看起来与 C# 代码中发生的情况相匹配,但实际上并非如此——正是因为如上所述编译器在幕后所做的事情。

确实,没有任何技术原因导致Expression.GreaterThanOrEqual朋友们无法检查他们的参数并生成与编译器将执行的操作相对应的完全相同的表达式树。例如,如果您传入两个等于该方法的ConstantExpression值,则该方法可以使用反射来确定与其参数相对应的数值,并且其行为就像您传入了该类型的常量表达式而不是抛出异常。它还可以处理一般情况(非常量子表达式)。TypeMyEnum

然而,这样做意味着表达式树的所见即所得属性会丢失:您会认为正在生成表达式树 X,而实际上您会生成不同的表达式树 Y。

这可能是完全理想的——并且您当然可以编写自己的方法来执行此操作——但作为默认行为,这可能不是一个好主意(一般来说,C# 的设计避开了 DWIM 心态,和/或会不能证明开发成本的合理性。请记住,在很多地方,编译器都会在视线之外完成繁重的工作,因此仅容纳这些场景的一个子集将是任意的,而容纳所有这些场景可能会令人望而却步。看看罗斯林的可用性是否会改变这一评估将会很有趣。