【问题标题】:Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object' of method 'Boolean Equals(System.Object)'“System.Int32”类型的表达式不能用于“Boolean Equals(System.Object)”方法的“System.Object”类型参数
【发布时间】:2014-04-15 07:38:11
【问题描述】:

我有一种常见的网格视图列过滤器方法,它可以明智地使用 ColumnName 和 SearchText 过滤网格视图记录。在这里,当我对可为空的 int 数据列进行操作时,此方法会引发错误,例如:

“System.Int32”类型的表达式不能用于“Boolean Equals(System.Object)”方法的“System.Object”类型参数

我的方法代码是:

 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;
    }
}

这是我发起的查询:

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();

在这里我包含了我的 query.GetType().ToString() 结果,以便更好地理解我对其进行操作的列的类型。

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

【问题讨论】:

  • 哪一行是异常?
  • 来自 group_id 案例的正文行。显示更新的问题

标签: c# .net linq linq-expressions


【解决方案1】:

编辑

this question 中找到了解决方案。在调用Equals(object)方法之前,需要将表达式转换为Object

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

Nicodemus13 建议首先将searchExpression 的类型明确设置为Object 也应该有效。

原创

我还没有发现问题,但我已经使用 Linqpad 在 SSCCE 中重现了该问题:

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;}}

这一行:

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

为方法Int32?.Equals (Object other) 返回一个MethodInfo。请注意,参数类型是object,而不是您可能期望的Int32(或Int32?)。

原因是typeof(Int32?)System.Nullable&lt;Int32&gt;,只有Equals(object)方法。

【讨论】:

  • 这行得通。但是在 FileSize,TotalFileSize 的情况下,我从来没有发现过这样的问题。
  • 我认为那是因为这些实际上并没有出现在您的查询中,所以相应的case 语句永远不会执行。
  • 如果我们使用 Int64,我们能否面临转换为对象之类的问题?。
  • 是的,Int64? 的行为方式与Int32? 相同,因此您需要再次将表达式转换为Object 类型。
  • 因为您的查询中没有 FileSizeTotalFileSize 属性。在处理它们的case 中放置一个断点,我敢打赌当你运行它时它不会被命中,所以它不会抛出错误。
【解决方案2】:

在 LinqPad 中玩这个,我认为问题出在:

searchExpression = Expression.Constant(_int1);

当你打电话时:

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

您尝试调用的Equals 方法是object.Equals(object),编译器告诉您int? 类型不是该方法期望的object 类型。

最简单的解决方法(虽然我不确定整个代码是否可以工作,尽管这个特定错误会消失)是将您调用的 Expression.Constant 的重载更改为指定 @987654328 的类型的重载@期望:

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

这将编译 - 但是,有几点需要注意。

  1. 您原来的Expression.Constant(_int1) 会产生ConstantExpressionType int 而不是int?。如果需要,您需要指定可为空的类型 (Expression.Constant(_int1, typeof(int?)))。但是,您仍然需要将其转换为 object,如上所述。

  2. 无论如何指定containsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) }); 都不应该起作用,因为没有这样的方法int?.Equals(int?)Equals 方法是System.Object 类上的方法的覆盖,它采用object 参数和是问题的根源。您也可以使用:typeof(object).GetMethod("Equals", new[] { typeof(object) });,因为这是正确的声明。

正如我所说,它应该用object 编译,代码是否符合您的预期,我不确定,但我认为是的。我期待看看它是否有效:)

【讨论】:

  • 谢谢你..它的作品。但是我怎么想知道我不需要这种用于 Int64 的技术?。
  • 您是说(您的)代码完全相同,但是将Int32? 替换为Int64? 不会引发原始异常?
  • 不替换意味着我已经有了 Int64?运行良好。为什么是 Int32?出现这样的错误。
  • 通过 :) 我不知道;我不明白为什么它会与一个而不是另一个一起工作。您的原始代码不应与 Int64? 一起使用
  • 我知道。因为我认为 Int64?如果我们正在使用 bigint。并且不需要强制转换为对象。
猜你喜欢
  • 2011-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多