我试图在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))
);
它抛出异常:
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转换为对象,但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.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#一样自动转换。