C# Linq 和相等运算符:“System.Int32”类型的表达式不能用于“System.Object”类型的参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/840150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:40:05  来源:igfitidea点击:

Linq and the Equality Operator: Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object'

c#.netlinqoperator-overloading

提问by CodingWithSpike

I'm trying to override the equality (==) operator in C# to handle comparing any type to a custom type (the custom type is really a wrapper/box around null).

我正在尝试覆盖 C# 中的相等 (==) 运算符以处理将任何类型与自定义类型进行比较(自定义类型实际上是围绕 null 的包装器/框)。

So I have this:

所以我有这个:

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;
    }
   ...
}

Now if I make a call like:

现在,如果我打电话给:

Nothing n = new Nothing();
bool equal = (10 == n);

It works perfectly fine. However, if I try to do this same thing through a Linq expression tree:

它工作得很好。但是,如果我尝试通过 Linq 表达式树来做同样的事情:

exp = Expression.Equal(
    Expression.Constant(10), 
    Expression.Constant(new Nothing(), typeof(Nothing))
);

It throws the 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)

Any ideas on why the base system can convert Int32 to Object, but Linq can't, or how I can fix this?

关于为什么基本系统可以将 Int32 转换为 Object,但 Linq 不能,或者我如何解决这个问题的任何想法?

This whole thing stared because Linq also can't compare Int32 to Object in the first place:

这整件事之所以引人注目,是因为 Linq 一开始也无法将 Int32 与 Object 进行比较:

exp = Expression.Equal(
    Expression.Constant(10), 
    Expression.Constant(null)
);

Throws an exception stating that there is no comparison operator for "System.Int32" and "System.Object".

引发异常,指出“System.Int32”和“System.Object”没有比较运算符。



Quick followup:

快速跟进:

The following do work without issue:

以下工作没有问题:

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)
);

So specifically casting everything to object. So does Linq just not handle inheritance internally? Thats pretty annoying...

所以专门将所有东西都投射到对象上。那么 Linq 只是不在内部处理继承吗?真烦人...



Followup #2:

后续行动#2:

I also tried using a custom comparison method:

我还尝试使用自定义比较方法:

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;
    }

This too throws an exception:

这也会引发异常:

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)

But again casting everything directly to object works:

但是再次将所有内容直接转换为对象工作:

exp = Expression.Equal(
    Expression.Constant(10, typeof(object)),
    Expression.Constant(null, typeof(object)),
    false,
    this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static)
);

So I guess I have my workaround... cast everything to object and use a custom comparison method. I'm still surprised Linq doesn't do the conversion automatically as normal C# does.

所以我想我有我的解决方法......将所有内容都投射到对象并使用自定义比较方法。我仍然很惊讶 Linq 没有像普通 C# 那样自动进行转换。

采纳答案by Marc Gravell

What is wrong with null? Re the missing intvs null, try int?:

null 有什么问题?重新缺少intvs null,请尝试int?

exp = Expression.Equal(
    Expression.Constant(10, typeof(int?)), 
    Expression.Constant(null, typeof(int?))
);

回答by Jay Pete

You should take a look at this article to check for a nullable type.

您应该查看本文以检查可空类型。

http://msdn.microsoft.com/en-us/library/ms366789.aspx

http://msdn.microsoft.com/en-us/library/ms366789.aspx