我正在尝试创建以下形式的表达式:
e => e.CreationDate;
CreationDate
的类型为long
,但我希望表达式返回object
。
我想使用object
作为返回类型,因为表达式是在运行时基于查询参数动态构建的。 query参数指定要在表达式中访问的属性,例如:
> 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);
我得到以下异常:
表达类型&Systems.Int64&#39;不能用于返回类型 &#39; System.Object的&#39;
很奇怪,因为据我所知,所有类型都从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 => e.CreationDate
的情况下实现object
?
答案 0 :(得分:1)
根据您使用result
的方式,您可以使用委托类型Func<Entity, long>
动态创建它,并将其键入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);
答案 1 :(得分:1)
简短的回答:不,这是不可能的。需要将值类型加框以将其视为对象。编译器通常会为您执行此操作,但如果您自己构建代码(例如表达式树),则需要将其指定为显式转换,就像您在找到的答案中看到的那样。如果您不能将它作为非泛型的LambdaExpression,我会在您期望MemberExpression或使用PropertyInfo的情况下另外处理转换情况,并仅在最后一刻构造orderby Expression。