【问题标题】:Expression of type 'System.Int64' cannot be used for return type 'System.Object'“System.Int64”类型的表达式不能用于返回类型“System.Object”
【发布时间】:2015-08-21 17:55:55
【问题描述】:

我正在尝试创建以下形式的表达式:

e => e.CreationDate;

CreationDate 的类型为 long,但我希望表达式返回 object

我想使用object 作为返回类型,因为表达式是在运行时根据查询参数动态构建的。查询参数指定表达式中要访问的属性,如:

> entities?order=creationDate
> entities?order=score

如您所见,我可以按具有不同类型的不同属性进行排序,因此返回类型 object 将允许我构建尽可能通用的表达式。

问题是当我尝试创建表达式时:

ParameterExpression entityParameter = Expression.Parameter(typeof(Entity), "e");
Expression propertyAccess = Expression.Property(entityParameter, property);
Expression<Func<Entity, object>> result = Expression.Lambda<Func<Entity, object>>(propertyAccess, entityParameter);

我得到以下异常:

“System.Int64”类型的表达式不能用于返回类型 '系统.对象'

这很奇怪,因为据我所知,所有类型都从object 扩展而来(表达式树似乎还不支持多态性)。

尽管如此,我在网上搜索并偶然发现了这个类似的问题:

Expression of type 'System.Int32' cannot be used for return type 'System.Object'

根据Jon Skeet的回答,我将最后一行修改为:

Expression<Func<Entity, object>> result = Expression.Lambda<Func<Entity, object>>(Expression.Convert(propertyAccess, typeof(object)), entityParameter);

这工作正常,但它不会生成我想要的表达式。相反,它会生成如下内容:

e => Convert(e.CreationDate)

我无法使用此解决方案,因为稍后在程序中,如果表达式主体不是MemberExpression(即成员访问操作),则会引发异常

我一直在互联网上寻找令人满意的答案,但没有找到。

如何实现e =&gt; e.CreationDate,返回类型为object

【问题讨论】:

  • 你需要构造一个Expression&lt;Func&lt;Entity, object&gt;&gt;吗?您可以创建一个非泛型 LambdaExpression 并改为构造一个 Func&lt;Entity, long&gt;
  • @Lee 我想使用相同的辅助方法来构建任何MemberExpression,这意味着有时我会返回long,有时会返回string。如果我不通用,那么我将不得不为每个返回类型或实现复制相同的方法逻辑
  • 你可以把它变成Expression&lt;Func&lt;Entity, TResult&gt;&gt;,类似于OrderBy in linq IQueryable
  • 如果你想对OrderBy使用这个表达式,有更好的方法,见stackoverflow.com/a/31959568/1847988

标签: c# .net linq reflection expression-trees


【解决方案1】:

根据您使用result 的方式,您可以使用委托类型Func&lt;Entity, long&gt; 动态创建它,并将其键入为LambdaExpression

ParameterExpression entityParameter = Expression.Parameter(typeof(Entity), "e");
Expression propertyAccess = Expression.Property(entityParameter, property);
var funcType = typeof(Func<,>).MakeGenericType(typeof(Entity), property.PropertyType);
LambdaExpression result = Expression.Lambda(funcType, propertyAccess, entityParameter);

【讨论】:

    【解决方案2】:

    简短回答:不,这是不可能的。值类型需要被装箱才能被视为对象。编译器通常会为您执行此操作,但如果您自己构建代码(例如表达式树),则需要将其指定为显式转换,就像您在找到的答案中看到的那样。如果您不能将其作为非泛型 LambdaExpression,我会在您期望 MemberExpression 的地方额外处理转换案例,或者使用 PropertyInfo,并仅在最后一刻构造 orderby 表达式。

    【讨论】:

      猜你喜欢
      • 2011-01-13
      • 1970-01-01
      • 1970-01-01
      • 2013-03-23
      • 1970-01-01
      • 1970-01-01
      • 2013-03-15
      • 1970-01-01
      相关资源
      最近更新 更多