Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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]]
like image 275
Shalin Gajjar Avatar asked Apr 15 '14 07:04

Shalin Gajjar


2 Answers

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.

like image 130
Rik Avatar answered Nov 12 '22 21:11

Rik


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

like image 2
nicodemus13 Avatar answered Nov 12 '22 21:11

nicodemus13