[英]c# Dynamic casting a List
我有一些遺留代碼,這些代碼試圖壓縮和刪除大量重復的代碼。 我有一個List<MessageItemViewModel>
作為從ASP.NET MVC POST操作調用的方法的參數。 實際的列表項將是MessageItemViewModel
的子類,例如。 MessageItemA1ViewModel
。 在被調用的方法中,該列表如下所示:
switch (level1Code)
{
case "A1":
{
var list = messages.Cast<MessageItemA1ViewModel>().ToList();
file = printHelper.Print(list).Save(exportFormat);
}
break;
case "A2":
{
var list = messages.Cast<MessageItemA2ViewModel>().ToList();
file = printHelper.Print(list).Save(exportFormat);
}
break;
case "A3":
總共大約有80種情況,但我想使用字典來減少它:
private readonly Dictionary<string, Type> _messageItemMap = new
Dictionary<string, Type>
{
{"A1", typeof(MessageItemA1ViewModel)},
{"A2", typeof(MessageItemA2ViewModel)},
{"A3", typeof(MessageItemA3ViewModel)},
並將列表項動態轉換為實際的基礎類型。 因此,我遵循了有關SO的示例,並且該方法通過聲明一個靜態方法並針對列表中的項目進行強制轉換,效果很好:
public static class Ext
{
public static T Cast<T>(this object entity) where T : class
{
return entity as T;
}
}
public class ExportHelper
{
public byte[] GetFile(string level1Code, string title, List<MessageItemViewModel> messages, ExportFormat exportFormat)
{
.
.
.
var castMethod = typeof(Ext).GetMethod("Cast", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(_messageItemMap[level1Code]);
var anItemType = castMethod.Invoke(null, new object[] { messages[0] });
anItemType
正確是我要轉換的實際類型。 在調試時,在即時窗口中,對anItemType is MessageItemA2ViewModel
的調用anItemType is MessageItemA2ViewModel
返回true。 但是我需要投射所有物品,所以我嘗試了這個:
var castMethod = typeof(Ext).GetMethod("Cast", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(_messageItemMap[level1Code]);
var theMessageItemModel = messages
.Select(p => castMethod.Invoke(null, new object[] { p }))
.Where(p => p != null)
.ToList();
最初這似乎是在懸停在theMessageItemModel
調試上,將值顯示為我轉換為的類型時起作用的,但這只是Visual Studio工具的魔力。 像以前一樣在即時窗口中檢查項目,這些項目實際上定義為System.Object,而且我還看到Linq調用的返回類型return List<Object>
。 以后會出現此問題,因為theMessageItemModel
被傳遞到另一個庫通用方法,在該方法中將調用TypeDescriptor.GetProperties(typeof(T))
以確定POCO的形狀以進行進一步的處理。 當作為List<Object>
傳入時,找到0個屬性,但是如果我可以將列表作為子類之一傳入,則可以。 List<MessageItemA1ViewModel>
則它將返回屬性。
誰能建議我應該如何使用Cast RuntimeMethodInfo創建與Type字典中的level1Code匹配的Type的正確類型列表?
===更新===實際上我沒有提到一件事,因為我要調用的庫方法是通用的,所以我也必須反映這一點,才能將動態類型轉換傳遞給Print方法:
var printMethod = printHelper.GetType().GetMethod("Print").MakeGenericMethod(theMessageItemModel.GetType().GetGenericArguments().Single());
var docRender = printMethod.Invoke(printHelper, new object[] { theMessageItemModel }) as IDocumentRender;
file = docRender.Save(exportFormat);
theMessageItemModel.GetType().GetGenericArguments().Single()
調用是找到並傳遞System.Object
地方,因為我的Linq調用重新廣播回List<System.Object>
好的,所以我對LINQ語句有更深入的思考。 因為在編譯時無法知道我的castMethod返回的內容,所以LINQ只能解析到Object范圍,因此我需要枚舉List才能在運行時真正解析它。 所以我意識到我可以將LINQ推送到我的Cast方法中:
public static IEnumerable<T> CastList<T>(this IEnumerable<object> entity) where T : class
{
var ret = entity
.Select(e => e as T)
.ToList();
return ret;
}
調用此方法時,它返回例如List<MessageItemA2ViewModel>
,現在我對List<MessageItemA2ViewModel>
theMessageItemModel.GetType().GetGenericArguments().Single()
調用實際上為List提供了子類類型,因此可以正確調用Print方法:
var castListMethod = typeof(Ext).GetMethod("CastList").MakeGenericMethod(_messageItemMap[level1Code]);
var theMessageItemModel = castListMethod.Invoke(null, new object[] { messages });
var printMethod = printHelper.GetType().GetMethod("Print").MakeGenericMethod(theMessageItemModel.GetType().GetGenericArguments().Single());
var docRender = printMethod.Invoke(printHelper, new [] { theMessageItemModel }) as IDocumentRender;
file = docRender.Save(exportFormat);
使用TypeDescriptor.GetProperties(typeof(T))
找到了12個屬性,最后我得到了預期的輸出。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.