测试对象是否是C#中的泛型类型

Ric*_*its 128 .net c# generics reflection types

如果对象是泛型类型,我想执行测试.我试过以下但没有成功:

public bool Test()
{
    List<int> list = new List<int>();
    return list.GetType() == typeof(List<>);
}
Run Code Online (Sandbox Code Playgroud)

我做错了什么,我该如何进行这项测试?

Meh*_*ari 184

如果要检查它是否是泛型类型的实例:

return list.GetType().IsGenericType;
Run Code Online (Sandbox Code Playgroud)

如果你想检查它是否是通用的List<T>:

return list.GetType().GetGenericTypeDefinition() == typeof(List<>);
Run Code Online (Sandbox Code Playgroud)

正如Jon指出的那样,这会检查确切的类型等价.返回false并不一定意味着list is List<T>返回false(即,不能将对象分配给List<T>变量).

  • 但这不会检测到亚型.看我的回答.它也更难接口:( (8认同)

Jon*_*eet 82

我假设您不仅想知道类型是否是通用的,而且如果对象是特定泛型类型的实例,而不知道类型参数.

不幸的是,它并不是非常简单.如果泛型类型是一个类(在这种情况下就是这样),那也不算太糟糕,但接口更难.这是一个类的代码:

using System;
using System.Collections.Generic;
using System.Reflection;

class Test
{
    static bool IsInstanceOfGenericType(Type genericType, object instance)
    {
        Type type = instance.GetType();
        while (type != null)
        {
            if (type.IsGenericType &&
                type.GetGenericTypeDefinition() == genericType)
            {
                return true;
            }
            type = type.BaseType;
        }
        return false;
    }

    static void Main(string[] args)
    {
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new List<string>()));
        // False
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new string[0]));
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new SubList()));
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new SubList<int>()));
    }

    class SubList : List<string>
    {
    }

    class SubList<T> : List<T>
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:如评论中所述,这可能适用于接口:

foreach (var i in type.GetInterfaces())
{
    if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
    {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个潜行的怀疑,可能会有一些尴尬的边缘情况,但我找不到它现在失败.

  • 你不能用对 IsAssignableFrom 的调用代替相等运算符 (`==`) 来替换 `IsInstanceOfGenericType` 中的循环吗? (3认同)
  • 刚刚发现了这个问题.它只归结为一行继承.顺便说一下,如果你有一个基类同时具有基类*和*你正在寻找的接口,那么这只是在类路径上. (2认同)

小智 6

您可以使用动态althougth来使用更短的代码,这可能比纯反射更慢:

public static class Extension
{
    public static bool IsGenericList(this object o)
    {
       return IsGeneric((dynamic)o);
    }

    public static bool IsGeneric<T>(List<T> o)
    {
       return true;
    }

    public static bool IsGeneric( object o)
    {
        return false;
    }
}



var l = new List<int>();
l.IsGenericList().Should().BeTrue();

var o = new object();
o.IsGenericList().Should().BeFalse();
Run Code Online (Sandbox Code Playgroud)


Wie*_*sma 5

这是我最喜欢的两种扩展方法,涵盖泛型类型检查的大多数边缘情况:

适用于:

  • 多个(通用)接口
  • 多个(通用)基类
  • 如果返回true,则具有将超出特定泛型类型的重载(请参阅样本的单元测试):

    public static bool IsOfGenericType(this Type typeToCheck, Type genericType)
    {
        Type concreteType;
        return typeToCheck.IsOfGenericType(genericType, out concreteType); 
    }
    
    public static bool IsOfGenericType(this Type typeToCheck, Type genericType, out Type concreteGenericType)
    {
        while (true)
        {
            concreteGenericType = null;
    
            if (genericType == null)
                throw new ArgumentNullException(nameof(genericType));
    
            if (!genericType.IsGenericTypeDefinition)
                throw new ArgumentException("The definition needs to be a GenericTypeDefinition", nameof(genericType));
    
            if (typeToCheck == null || typeToCheck == typeof(object))
                return false;
    
            if (typeToCheck == genericType)
            {
                concreteGenericType = typeToCheck;
                return true;
            }
    
            if ((typeToCheck.IsGenericType ? typeToCheck.GetGenericTypeDefinition() : typeToCheck) == genericType)
            {
                concreteGenericType = typeToCheck;
                return true;
            }
    
            if (genericType.IsInterface)
                foreach (var i in typeToCheck.GetInterfaces())
                    if (i.IsOfGenericType(genericType, out concreteGenericType))
                        return true;
    
            typeToCheck = typeToCheck.BaseType;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

这是一个演示(基本)功能的测试:

 [Test]
    public void SimpleGenericInterfaces()
    {
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IEnumerable<>)));
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IQueryable<>)));

        Type concreteType;
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IEnumerable<>), out concreteType));
        Assert.AreEqual(typeof(IEnumerable<string>), concreteType);

        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IQueryable<>), out concreteType));
        Assert.AreEqual(typeof(IQueryable<string>), concreteType);


    }
Run Code Online (Sandbox Code Playgroud)