簡體   English   中英

如何獲取IEnumerable上通用參數的類型 <object> ?

[英]How do I get the type of a generic parameter on IEnumerable<object>?

我創建了一個方法來告訴我通用IEnumerable中對象的類型是什么。 這似乎很簡單,但是當我嘗試將值集合從Dictionary傳遞給我的方法時,卻得到了意外的結果。 我想知道如何修復該方法以返回正確的結果,並且理想情況下,我還想解釋為什么我得到的結果。

//sample class (target type to get)
public class Person
{
    public string Name { get; set; }    
    public int Age { get; set; }
}

//method that extracts the type
public Type GetItemType(IEnumerable<object> collection)
{
    Type collectionType = collection.GetType();
    Type[] genericArguments = collectionType.GetGenericArguments();
    return genericArguments[0];
}

//sample data for test
var folk = new Dictionary<string, Person>();
folk.Add("Joe", new Person() { Name="Joseph Stalin", Age = 43 });
folk.Add("Tony", new Person() { Name="Winston Churchill", Age = 65 });

IEnumerable<Person> people = folk.Values;
Type itemType = GetItemType(people);

itemType是“ System.String”而不是“ Person”。 似乎是從實際的Dictionary中獲取類型通用參數,而不是值集合。

您面臨的問題是IEnumerable<object>后面有一個基礎類型,在您的情況下該類型是Dictionary<string, Person>.ValueCollection

您可以看到是否使用調試器並檢查collectionType 為了解決這個問題,您可以在初始化people時通過添加.ToList()將集合變成一個列表:

IEnumerable<Person> people = folk.Values.ToList();

現在, IEnumerable<object>后面的類型是List<Person> ,它應該為您提供所需的結果。

另一種“修復”是將您的方法簽名更改為:

public Type GetItemType<T>(IEnumerable<T> collection)

即使不將Values集合轉換為列表,也將返回Person類型。

這里的問題實際上是一個微妙的問題。 這是怎么回事的是,實際運行時類型folk.Values是一個嵌套類的Dictionary 具體來說就是Dictionary<string, Person>.ValueCollection 有效地將通用參數移到ValueCollection類型上,並且第一個最終是string

理想情況下,您真正​​需要做的就是更改方法簽名:

public Type GetItemType<T>( IEnumerable<T> collection )
{
    return typeof( T );
}

要解決此問題而不引入實際的通用參數,您需要執行以下操作:

public Type GetItemType(IEnumerable<object> collection)
{
    Type collectionType = collection.GetType();
    collectionType.Dump();

    return collectionType.GetInterfaces()
        .Where( iface => iface.IsGenericType )
        .Where( iface => iface.GetGenericTypeDefinition() == typeof( IEnumerable<> ) )
        .Select( iface => iface.GetGenericArguments()[0] ).FirstOrDefault();
}

在這種情況下,我們枚舉集合類型實現的接口以查找IEnumerable<> ,然后提取其通用參數。 請注意,如果您發現使用不同的通用參數類型多次實現IEnumerable<>的類型,則可能會遇到問題。

您的GetItemType方法獲取一個IEnumerable<object> 是否保證IEnumerable中的所有項目都屬於同一類型?

如果不是,則需要返回一個IEnumerable類型。 如果是,則只需要看第一個,然后返回collection.First().GetType()

這是您要找的東西嗎?

哦,實際上,請查看@ itsme86評論,這是一種更清潔的方式來做您想做的事

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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