Linq和Equality Operator:类型’System.Int32’的表达式不能用于’System.Object’类型的参数
我正在尝试覆盖C#中的相等(==)运算符来处理将任何类型与自定义类型进行比较(自定义类型实际上是一个围绕null的包装器/框)。
所以我有这个:
internal sealed class Nothing { public override bool Equals(object obj) { if (obj == null || obj is Nothing) return true; else return false; } public static bool operator ==(object x, Nothing y) { if ((x == null || x is Nothing) && (y == null || y is Nothing)) return true; return false; } ... }
现在,如果我打电话:
Nothing n = new Nothing(); bool equal = (10 == n);
它工作得非常好。 但是,如果我尝试通过Linq表达式树执行相同的操作:
exp = Expression.Equal( Expression.Constant(10), Expression.Constant(new Nothing(), typeof(Nothing)) );
它抛出了exception:
System.ArgumentException : Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object' of method 'Boolean op_Equality(System.Object, PARTSFinder.Rules.Runtime.RulesNothing)' at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodInfo method, ReadOnlyCollection`1& arguments) at System.Linq.Expressions.Expression.ValidateCallArgs(Expression instance, MethodInfo method, ReadOnlyCollection`1& arguments) at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments) at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments) at System.Linq.Expressions.ExpressionCompiler.GenerateBinaryMethod(ILGenerator gen, BinaryExpression b, StackType ask)
关于为什么基本系统可以将Int32转换为Object的任何想法,但Linq不能,或者我如何解决这个问题?
整个事情盯着看,因为Linq也无法首先将Int32与Object进行比较:
exp = Expression.Equal( Expression.Constant(10), Expression.Constant(null) );
引发exception,指出“System.Int32”和“System.Object”没有比较运算符。
快速跟进:
以下工作没有问题:
exp = Expression.Equal( Expression.Constant(10, typeof(object)), Expression.Constant(new Nothing(), typeof(Nothing)) ); exp = Expression.Equal( Expression.Constant(10, typeof(object)), Expression.Constant(null) );
所以专门将一切都投射到物体上 那么Linq内部没有处理inheritance吗? 多奇怪啊…
后续#2:
我也尝试过使用自定义比较方法:
exp = Expression.Equal( Expression.Constant(10), Expression.Constant(null), false, this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static) ); public static bool ValueEquals(object x, object y) { if (x == null && y == null) return true; if (x.GetType() != y.GetType()) return false; return x == y; }
这也引发了一个例外:
System.InvalidOperationException : The operands for operator 'Equal' do not match the parameters of method 'ValueEquals'. at System.Linq.Expressions.Expression.GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, Boolean liftToNull)
但是再次将所有内容直接投射到对象上:
exp = Expression.Equal( Expression.Constant(10, typeof(object)), Expression.Constant(null, typeof(object)), false, this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static) );
所以我想我有我的解决方法…将所有内容都转换为对象并使用自定义比较方法。 我仍然感到惊讶Linq没有像普通C#那样自动进行转换。
null有什么问题? 重新删除int
vs null
,尝试int?
:
exp = Expression.Equal( Expression.Constant(10, typeof(int?)), Expression.Constant(null, typeof(int?)) );
您应该查看本文以检查可以为空的类型。