Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Linq和相等运算符:类型为';System.Int32';不能用于类型为';System.Object';_C#_.net_Linq_Operator Overloading - Fatal编程技术网

C# Linq和相等运算符:类型为';System.Int32';不能用于类型为';System.Object';

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

我试图重写C#中的equality(=)操作符来处理将任何类型与自定义类型进行比较(自定义类型实际上是一个围绕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)
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)获得更好的权威@埃里克:谢谢你的确认,也谢谢你对林克为什么这样工作的一些见解。