代码之家  ›  专栏  ›  技术社区  ›  CodingWithSpike

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

  •  10
  • CodingWithSpike  · 技术社区  · 17 年前

    我试图重写C中的equality(==)运算符,以处理将任何类型与自定义类型进行比较(自定义类型实际上是一个包装器/包装盒,大约为空)。

    所以我有这个:

    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转换为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.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那样自动进行转换。

    2 回复  |  直到 12 年前
        1
  •  9
  •   Marc Gravell    17 年前

    空值有什么问题?重新失踪 int VS null 尝试 int? :

    exp = Expression.Equal(
        Expression.Constant(10, typeof(int?)), 
        Expression.Constant(null, typeof(int?))
    );
    
        2
  •  0
  •   Jay Pete    12 年前

    您应该看看本文来检查是否有可以为空的类型。

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