Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

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:

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?

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

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".


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


Followup #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.

like image 202
CodingWithSpike Avatar asked May 08 '09 14:05

CodingWithSpike


People also ask

Can operator ‘==’ be applied to operands of type?

[SOLVED] => Operator '==' cannot be applied to operands of type... I am getting this error 'Operator '==' cannot be applied to operands of type 'System.Guid' and 'string'' in linq to entityframework below code. in the below code CustomerId is Guid and customerProfileId is string. You cannot compare a Guid to a string directly.

Is it possible to get GUID string value in LINQ-to-entity query?

Normally I'd suggest: but ToString () doesn't exist in Linq to Entities. The answer to this question - Problem getting GUID string value in Linq-To-Entity query - will probably help.

What does LINQ mean?

The LINQ Project delivers Language Integrated Query (LINQ) for objects, relational, XML, and other forms of data. 1 0 Hi.


1 Answers

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

exp = Expression.Equal(
    Expression.Constant(10, typeof(int?)), 
    Expression.Constant(null, typeof(int?))
);
like image 78
Marc Gravell Avatar answered Oct 03 '22 04:10

Marc Gravell