C# 用于比较两个枚举值的Linq表达式
我正在我的应用程序中进行一些表达式构建,大部分时间都在运行。但当我尝试对枚举值进行比较运算时,遇到了麻烦。例如:C# 用于比较两个枚举值的Linq表达式,c#,linq-to-entities,C#,Linq To Entities,我正在我的应用程序中进行一些表达式构建,大部分时间都在运行。但当我尝试对枚举值进行比较运算时,遇到了麻烦。例如: expr = Expression.GreaterThanOrEqual(memberExpression, constExpression); 在memberExpression和constExpression属于MyEnum类型之前,此功能正常工作;这会引发运行时错误: 未为类型“MyNamespace.MyEnum”和“MyNamespace.MyEnum”定义二进制运算符G
expr = Expression.GreaterThanOrEqual(memberExpression, constExpression);
在memberExpression
和constExpression
属于MyEnum
类型之前,此功能正常工作;这会引发运行时错误:
未为类型“MyNamespace.MyEnum”和“MyNamespace.MyEnum”定义二进制运算符GreaterThanOrEqual
通过将枚举值转换为整数,我可以在其他地方绕过它,但不知何故,这似乎是错误的。如果我可以在C#中的
MyEnum
值之间进行比较操作,那么为什么表达式生成器不允许这样做
我可以通过转换枚举值在其他地方绕过它 对于整数,但不知何故,这似乎是错误的 感觉应该没错。毕竟,编译器本身就是这样做的——它要么用枚举值替换相应的数值(当枚举值在编译时已知时),要么生成代码,在运行时执行必要的强制转换。请注意,这些强制转换不一定是针对
int
,而是针对所讨论的枚举的支持类型
如果我可以在C#中的MyEnum
值之间进行比较运算,那么
为什么表达式生成器不允许它
您正在构建的表达式树看起来与C#代码中发生的事情相匹配,但实际上并不匹配——这正是因为编译器在上面提到的幕后所做的事情
确实,没有任何技术原因导致Expression.GreaterThanOrEqual
和friends无法检查其参数并生成与编译器所做操作完全相同的表达式树。例如,如果传入两个ConstantExpression
s,且Type
等于MyEnum
,则该方法可以使用反射来确定与其参数相对应的数值,其行为就像传入了该类型的常量表达式,而不是抛出。它还可以处理一般情况(非常量子表达式)
但是,这样做将意味着表达式树的WYSIWYG属性丢失:您可能会认为您正在生成表达式树X,而实际上您将生成不同的表达式树Y
这可能是非常理想的——您当然可以编写自己的方法来实现这一点——但这可能不是一个好主意,因为默认行为(一般来说,C#的设计避开了这种心态)和/或无法证明开发成本是合理的。请记住,在很多地方,编译器在看不见的情况下执行繁重的工作,因此只适应这些场景的一个子集是任意的,而适应所有场景可能是禁止的。很有意思的是,看看这个评估的可用性是否会改变。我最终没有转换成整数
private static void Example(string value, Type type, ParameterExpression pe, string propertyName)
{
Expression whereValue = null;
if (type.IsEnumOrNullableEnum())
{
whereValue = Expression.Constant(Enum.Parse(type, value));
}
Expression propExp = Expression.Property(pe, propertyName);
Expression ruleExpression = Expression.Equal(propExp, whereValue);//results in: item.MyEnum = A
}
可能是因为比较运算符强制转换为整数?“我可以通过将枚举值转换为整数来绕过它,但这似乎是错误的”=>为什么?枚举只不过是“带标签的数字”。显然,当你想比较这些值时,你就要比较数字。@Jon,我的观点正是这样;如果枚举只是带标签的数字,为什么表达式.GreaterThanOrEqual
会失败?@Shaul:我想这是因为在编写实时代码时,编译器会自动用值替换标签,而在构建表达式树时,您正处于完全手动模式:您编写的内容就是发生的,不会更多,也不会更少。因此,在编译时,Foo.Bar
被翻译成2<3
,但在表达式树中,您会得到两个Foo
类型的值,并且该类型没有定义小于运算符。@Shaul:当然,如果您有非恒定表达式,编译器会插入所需的强制转换(不能强制转换为int
,枚举也可以由其他类型支持)自动地,在表达式方面再次这样做会导致中等复杂的子树。如果Expression.GreaterThanOrEqual
以这种方式工作,你会认为你在添加一个节点,但在幕后你会添加一大堆东西。