一尘不染

如何检测类型是否为另一种通用类型

c#

例:

public static void DoSomething<K,V>(IDictionary<K,V> items) {
   items.Keys.Each(key => {
      if (items[key] **is IEnumerable<?>**) { /* do something */ }
      else { /* do something else */ }
}

不用反射就可以做到吗?我该怎么说C#中的IEnumerable?由于IEnumerable
<>实现了IEnumerable,我应该只使用IEnumerable吗?


阅读 330

收藏
2020-05-19

共1个答案

一尘不染

先前接受的答案很好,但这是错误的。值得庆幸的是,该错误很小。IEnumerable如果您真的想了解接口的通用版本,那么仅进行检查是不够的。有很多只实现非通用接口的类。一分钟后,我会给出答案。不过,首先,我想指出,所接受的答案过于复杂,因为在给定的情况下,以下代码将实现相同的效果:

if (items[key] is IEnumerable)

这样做的好处甚至更多,因为它分别适用于每个项目(而不适用于它们的公共子类V)。

现在,寻找正确的解决方案。这有点复杂,因为我们必须采用泛型IEnumerable1(即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。以下实施方式略有错误1,我仅将其留在 历史上
不要使用它
。取而代之的是,James在回答中提供了一个出色而正确的实现。

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);
}

1当与genericType相同时失败givenType。由于相同的原因,它对于可为空的类型也会失败,即

IsAssignableToGenericType(typeof(List<int>), typeof(List<>)) == false
IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false

我已经创建了包含一整套测试用例要点

2020-05-19