簡體   English   中英

如何投射IEnumerable <object> 到一個IEnumerable <runtime type>

[英]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>轉換為動態TypeIEnumerable

我應該注意,我的模型上不允許復雜的類型,所以像:

public ICollection<Tag> Tags { get; set; }

不會發生。 我只處理原始類型。

你對鑄造有一個基本的誤解。

必須在編譯時知道轉換操作的結果類型。 ¹

請考慮以下示例:

string a = "abc";
object b = (object)a;
string c = (string)b;

abc運行時類型是相同的。 這是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM