当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何检测类型是否是另一种通用类型》经验,为你挑选了3个好方法。

例:

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

这可以不使用反射吗?我怎么说C#中的IEnumerable?我应该只使用IEnumerable,因为IEnumerable <>实现IEnumerable?



1> 小智..:

非常感谢这篇文章.我想提供一个对我来说效果更好的Konrad Rudolph解决方案.我在该版本中遇到了一些小问题,特别是在测试Type是否为可为空的值类型时:

public static bool IsAssignableToGenericType(Type givenType, Type genericType)
{
    var interfaceTypes = givenType.GetInterfaces();

    foreach (var it in interfaceTypes)
    {
        if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
            return true;
    }

    if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
        return true;

    Type baseType = givenType.BaseType;
    if (baseType == null) return false;

    return IsAssignableToGenericType(baseType, genericType);
}


这很好但是如果你将直接比较移动到接口比较之上,如果直接比较匹配,那么这似乎会更快?

2> Konrad Rudol..:

以前接受的答案很好但是错了.值得庆幸的是,错误很小.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();
var ys = new System.Collections.ArrayList();
Console.WriteLine(IsGenericEnumerable(xs.GetType()));
Console.WriteLine(IsGenericEnumerable(ys.GetType()));

收益率:

True
False

不要过分担心这会使用反射.虽然这确实增加了运行时开销,但is运算符的使用也是如此.

当然,上面的代码非常有限,可以扩展为更普遍适用的方法IsAssignableToGenericType.以下实现略有不正确1,我将其留在这里仅用于历史目的.不要使用它.相反,詹姆斯在他的回答中提供了一个优秀,正确的实现.

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), typeof(List<>)) == false
IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false

我用一套全面的测试用例创建了一个要点.



3> Rich Visotck..:

关于泛型类型和使用IsAssignableFrom()的警告......

说你有以下内容:

public class MyListBase : IEnumerable where T : ItemBase
{
}

public class MyItem : ItemBase
{
}

public class MyDerivedList : MyListBase
{
}

在基本列表类型或派生列表类型上调用IsAssignableFrom将返回false,但显然是MyDerivedList继承MyListBase.(Jeff的快速说明,泛型绝对必须包含在代码块中或倾斜以获得,否则它被省略.这是有意吗?)问题源于MyListBase被视为完全不同类型的事实MyListBase.以下文章可以更好地解释这一点. http://mikehadlow.blogspot.com/2006/08/reflecting-generics.html

相反,请尝试以下递归函数:

    public static bool IsDerivedFromGenericType(Type givenType, Type genericType)
    {
        Type baseType = givenType.BaseType;
        if (baseType == null) return false;
        if (baseType.IsGenericType)
        {
            if (baseType.GetGenericTypeDefinition() == genericType) return true;
        }
        return IsDerivedFromGenericType(baseType, genericType);
    }

/编辑:Konrad的新帖子考虑了通用递归以及接口.非常好的工作.:)

/ EDIT2:如果检查genericType是否是接口,则可以实现性能优势.检查可以是当前接口代码的if块,但如果您对使用.NET 3.5感兴趣,我的一位朋友提供以下内容:

    public static bool IsAssignableToGenericType(Type givenType, Type genericType)
    {
        var interfaces = givenType.GetInterfaces().Where(it => it.IsGenericType).Select(it => it.GetGenericTypeDefinition());
        var foundInterface = interfaces.FirstOrDefault(it => it == genericType);
        if (foundInterface != null) return true;

        Type baseType = givenType.BaseType;
        if (baseType == null) return false;

        return baseType.IsGenericType ?
            baseType.GetGenericTypeDefinition() == genericType :
            IsAssignableToGenericType(baseType, genericType);
    }

推荐阅读
喜生-Da
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有