Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object' of method 'Boolean Equals(System.Object)'
Asked Answered
M

2

15

i have one common grid view column filter method that filter grid view record with ColumnName and SearchText wise. here when i operate on nullable int datacolumn there is error thrown from this method like :

Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object' of method 'Boolean Equals(System.Object)'

my method code is :

 public static IQueryable<T> FilterForColumn<T>(this IQueryable<T> queryable, string colName, string searchText)
{
    if (colName != null && searchText != null)
    {
        var parameter = Expression.Parameter(typeof(T), "m");
        var propertyExpression = Expression.Property(parameter, colName);
        System.Linq.Expressions.ConstantExpression searchExpression = null;
        System.Reflection.MethodInfo containsMethod = null;
        // this must be of type Expression to accept different type of expressions
        // i.e. BinaryExpression, MethodCallExpression, ...
        System.Linq.Expressions.Expression body = null;
        Expression ex1 = null;
        Expression ex2 = null;
        switch (colName)
        {
            case "JobID":
            case "status_id":
                Int32 _int = Convert.ToInt32(searchText);
                searchExpression = Expression.Constant(_int);
                containsMethod = typeof(Int32).GetMethod("Equals", new[] { typeof(Int32) });
                body = Expression.Call(propertyExpression, containsMethod, searchExpression);
                break;
            case "group_id":
                Int32? _int1 = Convert.ToInt32(searchText);
                searchExpression = Expression.Constant(_int1);
                containsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) });                     
                //Error throws from this line
                body = Expression.Call(propertyExpression, containsMethod, searchExpression);


                break;
            case "FileSize":
            case "TotalFileSize":
                Int64? _int2 = Convert.ToInt64(searchText);
                searchExpression = Expression.Constant(_int2);
                containsMethod = typeof(Int64?).GetMethod("Equals", new[] { typeof(Int64?) });
                body = Expression.Call(propertyExpression, containsMethod, searchExpression);
                break;
            // section for DateTime? properties
            case "PublishDate":
            case "Birth_date":
            case "Anniversary_date":
            case "Profile_Updated_datetime":
            case "CompletedOn":
                DateTime currentDate = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
                DateTime nextDate = currentDate.AddDays(1);
                ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate, typeof(DateTime?)));
                ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate, typeof(DateTime?)));
                body = Expression.AndAlso(ex1, ex2);
                break;
            // section for DateTime properties
            case "Created_datetime":
            case "Reminder_Date":
            case "News_date":
            case "thought_date":
            case "SubscriptionDateTime":
            case "Register_datetime":
            case "CreatedOn":
                DateTime currentDate1 = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
                DateTime nextDate1 = currentDate1.AddDays(1);
                ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate1));
                ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate1));
                body = Expression.AndAlso(ex1, ex2);
                break;
            default:
                searchExpression = Expression.Constant(searchText);
                containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                body = Expression.Call(propertyExpression, containsMethod, searchExpression);
                break;
        }
        var predicate = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });
        return queryable.Where(predicate);
    }
    else
    {
        return queryable;
    }
}

here is my query that i fired :

var query = Helper.GetUsers().Where(u => u.Id != user_id).OrderByDescending(u => u.Register_datetime).Select(u => new
                  {
                      Id = u.Id,
                      Name = u.First_name + " " + u.Last_name,
                      IsActive = u.IsActive,
                      IsVerified = u.IsVerified,
                      Username = u.Username,
                      password = u.password,
                      Birth_date = u.Birth_date,
                      Anniversary_date = u.Anniversary_date,
                      status_id = u.status_id,
                      group_id = u.group_id,
                      Profile_Updated_datetime = u.Profile_Updated_datetime,
                      Register_datetime = u.Register_datetime
                  }).FilterForColumn(ColumnName, SearchText).ToList();

here i include my query.GetType().ToString() result for better understanding types of columns that i operate on it.

System.Collections.Generic.List`1[<>f__AnonymousType0`12[System.Int32,System.String,System.Boolean,System.Boolean,System.String,System.String,System.Nullable`1[System.DateTime],System.Nullable`1[System.DateTime],System.Int32,System.Nullable`1[System.Int32],System.Nullable`1[System.DateTime],System.DateTime]]
Merlon answered 15/4, 2014 at 7:38 Comment(2)
what line is the exception?Budgie
from the body line of group_id case. show updated questionMerlon
C
19

EDIT

Found the solution in this question. You need to convert the expression to Object before calling the Equals(object)method:

var converted = Expression.Convert(searchExpression, typeof(object));
body = Expression.Call(propertyExpression, containsMethod, converted);

Nicodemus13's suggestion of explicitly setting searchExpression's type to Object in the first place should work, too.

Original

I haven't found the issue yet, but I have reproduced the problem in a SSCCE using Linqpad:

void Main()
{
    var myInstance = new myClass();
    var equalsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) });
    int? nullableInt = 1;
    var nullableIntExpr = System.Linq.Expressions.Expression.Constant(nullableInt);
    var myInstanceExpr = System.Linq.Expressions.Expression.Constant(myInstance);
    var propertyExpr = System.Linq.Expressions.Expression.Property(myInstanceExpr, "MyProperty");
    var result = Expression.Call(propertyExpr,equalsMethod,nullableIntExpr); // This line throws the exception.
    Console.WriteLine(result);
}

class myClass{public int? MyProperty{get;set;}}

This line:

containsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) });

returns a MethodInfo for the method Int32?.Equals (Object other). Notice the parameter type is object, not Int32 (or Int32?) as you might expect.

The reason is typeof(Int32?) is System.Nullable<Int32>, which only has the Equals(object) method.

Cynthla answered 15/4, 2014 at 9:6 Comment(5)
this works. but how ever at cases of case FileSize,TotalFileSize i never found any problem like this.Merlon
I think that's because those don't actually appear in your query, so the corresponding case statement is never executed.Cynthla
Can we face issue like converting to object in case we work with Int64?.Merlon
Yes, the Int64?will behave the same way as Int32?, so you would need to convert the expression to type Object again.Cynthla
Because there's no FileSize or TotalFileSize property in your query. Put a breakpoint in the case handling them, and I bet it will not get hit when you run it, so it won't throw an error.Cynthla
D
4

Playing around with this in LinqPad, I think the problem is around:

searchExpression = Expression.Constant(_int1);

when you call:

containsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) });

The Equals method you're attempting to call is object.Equals(object) and the compiler is telling you that the type int? is not the type object that the method expects.

The simplest fix (though I'm not sure that the overall code will work, though this particular error will go away) is to change the overload of the Expression.Constant that you call to one that specifies the type that Equals expects:

searchExpression = Expression.Constant(_int1, typeof(object));

This will compile- however, there's a few things to note.

  1. Your original Expression.Constant(_int1) results in a ConstantExpression with Type int not int?. You'd need to specify the nullable type, if you needed that (Expression.Constant(_int1, typeof(int?))). However, you'll need to cast it to object anyway, as above.

  2. Specifying containsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) }); shouldn't work anyway, as there's not such method int?.Equals(int?), the Equals method is the override of the method on the System.Object class which takes an object parameter and is the root of the problem. You may as well use: typeof(object).GetMethod("Equals", new[] { typeof(object) }); as that's the correct declaration.

As I said, it should compile with object, whether the code does what you expect, I'm not sure, but I think so. I look forward to seeing whether it works :)

Demodulate answered 15/4, 2014 at 10:0 Comment(5)
thank u..it's works. but how ever i wonder i don't need this technique used for Int64?.Merlon
You're saying that (your) exactly the same code, but replacing Int32? with Int64? doesn't throw the original exception?Demodulate
not replacing means i have already Int64? which is running fine. why Int32? getting error like that.Merlon
Pass :) I don't know; I can't see why it would work with one and not the other. Your original code shouldn't work with Int64?Demodulate
ya i know. Because i think Int64? works with if we are working with bigint. And it is not required for casting to object.Merlon

© 2022 - 2024 — McMap. All rights reserved.