我正在嘗試創建以下形式的表達式:
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);
我得到以下異常:
“System.Int64”類型的表達式不能用於返回類型“System.Object”
這很奇怪,因為據我所知,所有類型都從object
擴展(似乎表達式樹還沒有支持多態)。
然而,我在網上搜索並偶然發現了類似的問題:
類型'System.Int32'的表達式不能用於返回類型'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
(即成員訪問操作),程序後面會拋出異常
我一直在互聯網上搜索一個令人滿意的答案,但找不到任何答案。
如何在返回類型為object
e => e.CreationDate
下實現e => e.CreationDate
?
根據您使用result
您可以使用委託類型Func<Entity, long>
動態創建它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);
簡答:不,這是不可能的。需要將值類型加框以將其視為對象。編譯器通常會為您執行此操作,但如果您自己構建代碼(例如表達式樹),則需要將其指定為顯式轉換,就像您在找到的答案中看到的那樣。如果您不能將它作為非泛型的LambdaExpression,我會在您期望MemberExpression或使用PropertyInfo的情況下另外處理轉換情況,並僅在最後時刻構造orderby Expression。