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

C# 在C中测试对象是否为泛型类型#,c#,.net,generics,reflection,types,C#,.net,Generics,Reflection,Types,如果对象是泛型类型,我想执行一个测试。我尝试了以下方法但没有成功: public bool Test() { List<int> list = new List<int>(); return list.GetType() == typeof(List<>); } 公共布尔测试() { 列表=新列表(); return list.GetType()==typeof(list); } 我做错了什么?如何执行此测试?如果要检查它是否是泛型类型的实

如果对象是泛型类型,我想执行一个测试。我尝试了以下方法但没有成功:

public bool Test()
{
    List<int> list = new List<int>();
    return list.GetType() == typeof(List<>);
}
公共布尔测试()
{
列表=新列表();
return list.GetType()==typeof(list);
}

我做错了什么?如何执行此测试?

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

return list.GetType().IsGenericType;

如果要检查它是否是通用的
列表

返回list.GetType().GetGenericTypeDefinition()==typeof(list);

正如Jon指出的,这检查了确切的类型等价性。返回
false
并不一定意味着
list is list
返回
false
(即不能将对象分配给
list
变量)

我假设您不只是想知道类型是否为泛型,而是想知道对象是否是特定泛型类型的实例,而不知道类型参数

不幸的是,这并不十分简单。如果泛型类型是一个类(在本例中就是这样),这并不太糟糕,但是对于接口来说就更难了。下面是一个类的代码:

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>
    {
    }
}

我有一个潜在的怀疑,这可能有一些尴尬的边缘案例,但我现在找不到一个它失败的案例。

您可以使用动态的较短代码,尽管这可能比纯反射慢:

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();
公共静态类扩展
{
公共静态bool IsGenericList(此对象为o)
{
返回IsGeneric((动态)o);
}
公共静态布尔是通用的(列表o)
{
返回true;
}
公共静态bool是通用的(对象o)
{
返回false;
}
}
var l=新列表();
l、 IsGenericList().Should().BeTrue();
var o=新对象();
o、 IsGenericList().Should().BeFalse();

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

与以下机构合作:

  • 多(通用)接口
  • 多个(通用)基类
  • 具有一个重载,如果它返回true,将“输出”特定的泛型类型(请参阅单元测试以获取示例):

下面是演示(基本)功能的测试:

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


    }
[测试]
public void simplegeneriinterfaces()
{
IsTrue(typeof(Table).IsOfGenericType(typeof(IEnumerable));
Assert.IsTrue(typeof(Table).IsOfGenericType(typeof(IQueryable));
具体类型;
IsTrue(typeof(Table).IsOfGenericType(typeof(IEnumerable),out-concreteType));
AreEqual(typeof(IEnumerable),concreteType);
IsTrue(typeof(Table).IsOfGenericType(typeof(IQueryable),out-concreteType));
AreEqual(typeof(IQueryable),concreteType);
}

但不会检测子类型。看看我的答案。接口也更难:(如果不是泛型类型,对GetGenericTypeDefinition的调用将抛出。请确保先检查它。@jonsket您可以使用
list.GetType()检测子类型).BaseType
属性。@MohammedLarabi:是的,这正是我的答案所做的,递归地…它对于不同的问题是正确的。对于这个问题,它是不正确的,因为它只解决了(明显少于)一半的问题。Stan R的答案实际上回答了提出的问题,但OP真正的意思是什么“测试对象在C#中是否属于特定的泛型类型”,对此的回答确实不完整。人们反对我,因为我在“是”泛型类型而不是“是”泛型类型的上下文中回答了这个问题“泛型。英语是我的第二语言,这种语言的细微差别经常会从我身边溜走,为了我的辩护,OP没有特别要求针对特定的类型进行测试,在标题中问“是的”泛型类型…不知道为什么我会因为一个模棱两可的问题而被否决。现在你知道了,你可以改进你的答案,使之更具体、更正确。刚刚发现了一个问题。它只涉及一行继承。如果你有一个既有基类又有你正在寻找的接口的基类,那么就这样仅在类路径下。@Groxx:True。我刚刚发现我在回答中确实提到了这一点:“如果泛型类型是类(在本例中是这样),这并不太糟糕,但对于接口来说更难。下面是类的代码”如果你没有办法知道怎么办?比如,它可能是int或string,但你不知道。这似乎会产生误判…所以你没有t可使用,你只是在查看某个对象的属性,其中一个是列表。你怎么知道它是一个列表,这样你就可以取消对它的感知?我的意思是,你没有任何地方也没有要使用的类型。您可以猜测每种类型(是列表吗?是列表吗?)但是你想知道的是这是一个列表吗?这个问题似乎很难回答。@RiverC:是的,你是对的-这很难回答,因为各种原因。如果你只谈论一个类,那也不算太糟糕……你可以继续沿着继承树走,看看你是否以某种形式点击了
LIST
rfaces,这真的很棘手。你不能用调用
IsAssignableFrom
而不是相等运算符(
=
)来替换
IsInstanceOfGenericType
中的循环吗?
foreach (var i in type.GetInterfaces())
{
    if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
    {
        return true;
    }
}
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();
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;
    }
}
 [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);


    }