2012-10-04 44 views
8

可能重複的基本類型:
getting type T from IEnumerable<T>如何獲得的IEnumerable

我有IEnumerable

public IEnumerable PossibleValues { get; set; }

我怎樣才能找到一個屬性類型它被實例化的基類型?

例如,如果有人這樣創建:

PossibleValues = new int?[] { 1, 2 } 

我想知道的類型是「詮釋」。

+5

@Arran,指通用版本 –

+0

@Arran:不一定,如果有在該方面,任何意義的是,OP顯示可空''的一個數組,但想要檢索'int'。 –

+0

阿真,不理我了:) – Arran

回答

3

如果你想PossibleValues的類型,你可以這樣做:

var type = PossibleValues.GetType().ToString(); // "System.Nullable`1[System.Int32][]" 

或者,如果你想在描述包含在PossibleValues(假設數組實際上具有價值的項目的類型,你可以做到這一點你問題):

var type = PossibleValues.Cast<object>().First().GetType().ToString(); // "System.Int32" 



編輯

如果它是一種可能性,即該陣列可以包含項目,那麼你就必須做的,當然一些空的檢查,:

var firstItem = PossibleValues.Cast<object>().FirstOrDefault(o => o != null); 
var type = string.Empty; 
if (firstItem != null) 
{ 
    type = firstItem.GetType().ToString(); 
} 
+0

您需要在拉第一個之前檢查序列是否有值。 – Servy

+1

這就是爲什麼我說「假設陣列實際上有價值」。 – bugged87

+0

如果它不具有價值應該可能只是沒有拿出一個類型(仍然沒有工作),而不是拋出異常。 – Servy

8
Type GetBaseTypeOfEnumerable(IEnumerable enumerable) 
{ 
    if (enumerable == null) 
    { 
     //you'll have to decide what to do in this case 
    } 

    var genericEnumerableInterface = enumerable 
     .GetType() 
     .GetInterfaces() 
     .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)); 

    if (genericEnumerableInterface == null) 
    { 
     //If we're in this block, the type implements IEnumerable, but not IEnumerable<T>; 
     //you'll have to decide what to do here. 

     //Justin Harvey's (now deleted) answer suggested enumerating the 
     //enumerable and examining the type of its elements; this 
     //is a good idea, but keep in mind that you might have a 
     //mixed collection. 
    } 

    var elementType = genericEnumerableInterface.GetGenericArguments()[0]; 
    return elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(Nullable<>) 
     ? elementType.GetGenericArguments()[0] 
     : elementType; 
} 

這個例子有一定的侷限性,這可能會或可能不會涉及您的申請。它不處理類型實現IEnumerable但不是IEnumerable<T>的情況。如果該類型不止一次執行IEnumerable<T>,則它會任意選擇一個實現。

+0

謝謝,當我有足夠的聲譽,我提出你的答案。 –

+0

我正在使用另一個答案,但學習很好。 –

+0

@RaoniZacaron我已經提高了你的問題,所以你現在有足夠的聲望來提出答案(祝賀)。不要忘記接受你正在使用的答案! – phoog

2

現有的兩種方法是查看對象是否實現了IEnumerable<T>或檢查集合中第一個項目的類型。第一個依賴於實際實現IEnumerable<T>的對象,而第二個僅適用於序列中的所有項都具有相同派生類型的情況。

您可能會問的一個有趣的問題是所有項目具有什麼類型的共同點,或者哪些是所有項目中最常見的最窄類型。

我們將從一個簡單的輔助方法開始。給定一個類型,它將返回一個該類型的序列及其所有基類型。

public static IEnumerable<Type> getBaseTypes(Type type) 
{ 
    yield return type; 

    Type baseType = type.BaseType; 
    while (baseType != null) 
    { 
     yield return baseType; 
     baseType = baseType.BaseType; 
    } 
} 

下一步,我們將有一個方法,通過首先找到所有最派生類型,然後讓所有的基本類型爲每種類型的序列中獲得所有常見類型的序列,最後使用intersect只得到他們都有共同的項目:

public static IEnumerable<Type> getCommonTypes(IEnumerable source) 
{ 
    HashSet<Type> types = new HashSet<Type>(); 
    foreach (object item in source) 
    { 
     types.Add(item.GetType()); 
    } 

    return types.Select(t => getBaseTypes(t)) 
     .Aggregate((a, b) => a.Intersect(b)); 
} 

注意,類型的第一種方法的順序是從最派生到最少導出,Intersect保持排序,因此產生的順序將是從大多數派生到最小派生。如果你想找到所有這些類型通用的最窄類型,那麼你可以簡單地使用First這個方法的結果。 (請注意,因爲所有東西都來自object,所以在這裏總會有至少一種類型返回,除非原始IEnumerable中沒有項目。