C# Linq和相等运算符:类型为';System.Int32';不能用于类型为';System.Object';
我试图重写C#中的equality(=)操作符来处理将任何类型与自定义类型进行比较(自定义类型实际上是一个围绕null的包装器/框) 所以我有这个:C# Linq和相等运算符:类型为';System.Int32';不能用于类型为';System.Object';,c#,.net,linq,operator-overloading,C#,.net,Linq,Operator Overloading,我试图重写C#中的equality(=)操作符来处理将任何类型与自定义类型进行比较(自定义类型实际上是一个围绕null的包装器/框) 所以我有这个: internal sealed class Nothing { public override bool Equals(object obj) { if (obj == null || obj is Nothing) return true; else
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))
);
它抛出异常:
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)
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)
关于为什么基本系统可以将Int32转换为Object,而Linq不能,或者我如何解决这个问题,有什么想法吗
这整件事之所以会发生,是因为Linq也无法将Int32与Object进行比较:
exp = Expression.Equal(
Expression.Constant(10),
Expression.Constant(null)
);
引发异常,指出“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只是不在内部处理继承吗?这很烦人
后续行动#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.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)
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)
但同样,将所有内容直接投射到object works:
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
与null
,尝试int?
:
exp = Expression.Equal(
Expression.Constant(10, typeof(int?)),
Expression.Constant(null, typeof(int?))
);
您应该看看这篇文章,检查是否存在可为null的类型
我的问题是我真的不知道这些类型。表达式.Constant是根据字典中的值动态生成的。问题是当字典中不存在某个内容时,它会返回null。为了进一步澄清我的上述评论,有人可以尝试比较“x”和“y”,代码会从字典中提取“x”和“y”,并生成一个表达式。常量(dict[“x”])和表达式。常量(dict[“y”]),并尝试将它们相等。好吧,使用“object”在表达上有点冒险;它需要证明类型以使用正确的重载。。。您可能需要加入一些特殊的规则,以便在一个操作数为null时使用另一个操作数的类型。“那么Linq只是不在内部处理继承吗?这很烦人…”是的,这很烦人,但这是有充分理由的。表达式树库处理来自C#和VB的表达式,以及任何其他具有此类表达式的语言。如果我们将C#转换规则烘焙到处理等式解析的代码中,那么对于来自VB的表达式,我们可能做了错误的事情。所以我们两者都不做——你需要传递明确的表达,这样决议就不受语言的影响了。(补充你的评论)好吧,在这个问题上,你不会比埃里克·利珀特(Eric Lippert)获得更好的权威@埃里克:谢谢你的确认,也谢谢你对林克为什么这样工作的一些见解。