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