The previously accepted answer是好的,但它是錯誤的。謝天謝地,這個錯誤是一個小問題。如果您真的想知道接口的通用版本,檢查IEnumerable
是不夠的;有很多類僅實現非通用接口。我會在一分鐘內給出答案。不過,首先我想指出的是,公認的答案是過於複雜,因爲下面的代碼將實現在特定情況下是相同的:
if (items[key] is IEnumerable)
這確實更因爲它分別適用於每個項目(而不是它們的共同子類,V
)。
現在,爲正確的解決方案。這是一個比較複雜一點,因爲我們必須採取泛型類型IEnumerable`1
(即用一個類型參數的類型IEnumerable<>
),並注入正確的通用說法:
static bool IsGenericEnumerable(Type t) {
var genArgs = t.GetGenericArguments();
if (genArgs.Length == 1 &&
typeof(IEnumerable<>).MakeGenericType(genArgs).IsAssignableFrom(t))
return true;
else
return t.BaseType != null && IsGenericEnumerable(t.BaseType);
}
您可以輕鬆地測試此代碼的正確性:
var xs = new List<string>();
var ys = new System.Collections.ArrayList();
Console.WriteLine(IsGenericEnumerable(xs.GetType()));
Console.WriteLine(IsGenericEnumerable(ys.GetType()));
產量:
True
False
不要過分受這個使用反射的事實有關。雖然確實會增加運行時間開銷,但使用is
運算符也是如此。
當然,上面的代碼是非常有限的,可以擴展到一個更普遍適用的方法,IsAssignableToGenericType
。下面的實現是有點不正確的,我會在這裏留下它僅用於歷史目的。 請勿使用。相反,James has provided an excellent, correct implementation in his answer.
public static bool IsAssignableToGenericType(Type givenType, Type genericType) {
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
if (it.IsGenericType)
if (it.GetGenericTypeDefinition() == genericType) return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == genericType ||
IsAssignableToGenericType(baseType, genericType);
}
當genericType
相同givenType
它將失敗;出於同樣的原因,它不能爲空類型,即
IsAssignableToGenericType(typeof(List<int>), typeof(List<>)) == false
IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false
我創建了一個gist with a comprehensive suite of test cases。
這正是我所期待的。謝謝! 它仍然使用反射,但我正在尋找「typeof(IEnumerable <>)」語法。謝謝! – 2008-09-16 18:47:03
除了使用「is」之外,沒有其他方法可以對類型進行檢查嗎? – 2008-09-16 19:22:21
最後一行應該是`return(baseType.IsGenericType && baseType.GetGenericTypeDefinition()== genericType)|| IsAssignableToGenericType(baseType,genericType);`僅僅因爲基類是泛型的,你無法避免遞歸。 – 2010-09-22 03:53:53