[英]How to cast an IEnumerable<object> to an IEnumerable<runtime type>
我正在努力完成以下任務。
假設我有這個數據模型:
public class Article
{
public ICollection<string> Tags { get; set; }
}
從數據庫中檢索這些標記。 我的數據庫的API將它們作為List<object>
返回給我。
因此,我需要從List<object>
轉換為實現ICollection<string>
。
我知道LINQ Cast<T>()
方法將其元素Cast<T>()
轉換為給定類型並返回轉換后的IEnumerable<T>
。
但是,我不能使用Cast<string>()
因為它總是將我的List<object>
Cast<string>()
為IEnumerable<string>
,而不為具有ICollection<double>
屬性(或任何其他類型)的模型提供任何選項。
我可以使用反射並獲取泛型類型參數:
Type genericArg = collectionType.GetGenericArguments().First();
但這會讓我得到一個運行時Type
,我不能用它作為Cast<genericArg>()
。
如何將IEnumerable<object>
轉換為動態Type
的IEnumerable
?
我應該注意,我的模型上不允許復雜的類型,所以像:
public ICollection<Tag> Tags { get; set; }
不會發生。 我只處理原始類型。
你對鑄造有一個基本的誤解。
必須在編譯時知道轉換操作的結果類型。 ¹
請考慮以下示例:
string a = "abc";
object b = (object)a;
string c = (string)b;
a
, b
和c
的運行時類型是相同的。 這是string
。 編譯時類型不同。 轉換僅與編譯時類型相關。
因此,你的問題的答案
如何將
IEnumerable<object>
IEnumerable<runtime type>
轉換為IEnumerable<runtime type>
是:你沒有。 對於運行時類型,強制轉換沒有意義。
也就是說,讓我為您的實際問題提供一個解決方案:假設您有一個IEnumerable<object> values
,一個Type myTargetType
並希望創建一個包含值的List<typeof(myTargetType)>
。
首先,使用反射創建列表:
var listType = typeof(List<>).MakeGenericType(myTargetType);
IList myList = (IList)Activator.CreateInstance(listType);
然后你填寫清單:
foreach (var item in values)
{
myList.Add(item);
}
顯然,如果values
的條目不是運行時類型myTargetType
,則Add
將拋出ArgumentException 。
¹結果類型可以是泛型類型,但也必須在編譯時指定泛型類型參數 。
我相信System.Convert有你需要的東西:
Type genericArg = collectionType.GetGenericArguments().First();
foreach(var obj in collection) {
yield return Convert.ChangeType(obj, genericArg);
}
Enumerable.Cast<T>(this IEnumerable source)
通常是你要找的東西。 如果需要不同的變化,可以使用反射來自行關閉泛型類型:
class Program
{
static void Main(string[] args)
{
var source = new List<object> {
"foo",
"bar",
"baz"
};
var type = typeof(string); // or however you find out the type
var castMethod = typeof(Enumerable)
.GetMethod("Cast").MakeGenericMethod(
new[] {
type
});
var result = (IEnumerable<string>)
castMethod.Invoke(null, new object[] {source});
foreach (var str in result)
{
Console.WriteLine(str.ToUpper());
}
}
}
另一個問題是從一個List<T>
到另一個List<T>
沒有意義 - 泛型參數是不變的 ,因為該集合是讀寫的。 (由於歷史原因,數組允許一些這樣的轉換。)但是,如果你只是閱讀,那么從Cast
返回的IEnumerable<T>
就足夠了。
您需要實現一個通用方法,該方法從數據庫api中獲取結果並根據您的模型返回適當的集合,如下所示:
private ICollection<T> RetrieveTags()
{
// Get tags using database api
return tags.Cast<T>();
}
然后調用此方法以根據需要獲取模型,例如:
ICollection<int> t1 = RetrieveTags<int>();
ICollection<string> t2 = RetrieveTags<string>();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.