Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object' of method 'Boolean Equals(System.Object)'
Solution 1
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.
Solution 2
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.
Your original
Expression.Constant(_int1)
results in aConstantExpression
withType
int
notint?
. You'd need to specify the nullable type, if you needed that (Expression.Constant(_int1, typeof(int?))
). However, you'll need to cast it toobject
anyway, as above.Specifying
containsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) });
shouldn't work anyway, as there's not such methodint?.Equals(int?)
, theEquals
method is the override of the method on theSystem.Object
class which takes anobject
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 :)
Shalin Gajjar
Updated on August 04, 2022Comments
-
Shalin Gajjar almost 2 years
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]]
-
Shalin Gajjar about 10 yearsthank u..it's works. but how ever i wonder i don't need this technique used for Int64?.
-
Shalin Gajjar about 10 yearsthis works. but how ever at cases of case FileSize,TotalFileSize i never found any problem like this.
-
Rik about 10 yearsI think that's because those don't actually appear in your query, so the corresponding
case
statement is never executed. -
nicodemus13 about 10 yearsYou're saying that (your) exactly the same code, but replacing
Int32?
withInt64?
doesn't throw the original exception? -
Shalin Gajjar about 10 yearsnot replacing means i have already Int64? which is running fine. why Int32? getting error like that.
-
Shalin Gajjar about 10 yearsCan we face issue like converting to object in case we work with Int64?.
-
nicodemus13 about 10 yearsPass :) 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?
-
Shalin Gajjar about 10 yearsya i know. Because i think Int64? works with if we are working with bigint. And it is not required for casting to object.
-
Rik about 10 yearsYes, the
Int64?
will behave the same way asInt32?
, so you would need to convert the expression to typeObject
again. -
Rik about 10 yearsBecause there's no
FileSize
orTotalFileSize
property in your query. Put a breakpoint in thecase
handling them, and I bet it will not get hit when you run it, so it won't throw an error.