在 C# 中测试对象是不是属于泛型类型
Posted
技术标签:
【中文标题】在 C# 中测试对象是不是属于泛型类型【英文标题】:Testing if object is of generic type in C#在 C# 中测试对象是否属于泛型类型 【发布时间】:2010-11-02 05:18:12 【问题描述】:我想测试一个对象是否属于泛型类型。我尝试了以下方法但没有成功:
public bool Test()
List<int> list = new List<int>();
return list.GetType() == typeof(List<>);
我做错了什么以及如何执行此测试?
【问题讨论】:
【参考方案1】:如果要检查它是否是泛型类型的实例:
return list.GetType().IsGenericType;
如果你想检查它是否是通用的List<T>
:
return list.GetType().GetGenericTypeDefinition() == typeof(List<>);
正如 Jon 所指出的,这会检查确切的类型等价性。返回false
并不一定意味着list is List<T>
返回false
(即不能将对象分配给List<T>
变量)。
【讨论】:
虽然不会检测到子类型。看我的回答。接口也更难:( 如果 GetGenericTypeDefinition 不是泛型类型,调用将抛出。请务必先检查。 @JonSkeet 您可以使用list.GetType().BaseType
属性检测子类型。
@MohammedLarabi:是的,这正是我的答案所做的,递归......【参考方案2】:
return list.GetType().IsGenericType;
【讨论】:
对于不同的问题是正确的。对于这个问题,它是不正确的,因为它只解决了(大大少于)一半的问题。 Stan R 的回答实际上回答了所提出的问题,但 OP 的真正意思是“测试对象是否属于 C# 中的 特定 泛型类型”,为此这个答案确实不完整。 人们对我投了反对票,因为我在“是”泛型类型而不是“是”泛型类型的上下文中回答了这个问题。英语是我的第二语言,这种语言的细微差别经常让我忽略,为我辩护的是,OP 并没有特别要求针对特定类型进行测试,并且在标题中询问“属于”通用类型......不知道为什么我应该投反对票一个模棱两可的问题。 现在您知道了,您可以改进您的答案,使其更加具体和正确。【参考方案3】:我假设您不仅想知道类型是否是泛型,还想知道对象是否是特定泛型类型的实例,而不知道类型参数。
不幸的是,这并不是非常简单。如果泛型类型是一个类(在这种情况下就是这样),那还不错,但对于接口来说就更难了。这是一个类的代码:
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>
编辑:如 cmets 中所述,这可能适用于接口:
foreach (var i in type.GetInterfaces())
if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
return true;
我偷偷怀疑这可能存在一些尴尬的边缘情况,但我现在找不到它失败的情况。
【讨论】:
刚刚发现这个问题。它只沿着单行继承。如果在此过程中,您有一个包含基类 和 您正在寻找的接口的基础,那么这只会沿着类路径。 @Groxx:是的。我刚刚发现我确实在答案中提到了这一点:“如果泛型类型是一个类(在这种情况下就是这样),这还不错,但对于接口来说更难。这是一个类的代码”跨度> 如果你没有办法知道List<T>
。如果包含接口,那真的很棘手。
您不能用调用IsAssignableFrom
而不是相等运算符(==
) 来替换IsInstanceOfGenericType
中的循环吗?【参考方案4】:
您可以使用动态代码来使用较短的代码,尽管这可能比纯反射慢:
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();
【讨论】:
【参考方案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;
这是一个演示(基本)功能的测试:
[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);
【讨论】:
【参考方案6】:public static string WhatIsMyType<T>()
return typeof(T).NameWithGenerics();
public static string NameWithGenerics(this Type type)
if (type == null)
throw new ArgumentNullException(nameof(type));
if (type.IsArray)
return $"type.GetElementType()?.Name[]";
if (!type.IsGenericType)
return type.Name;
var name = type.GetGenericTypeDefinition().Name;
var index = name.IndexOf('`');
var newName = index == -1 ? name : name.Substring(0, index);
var list = type.GetGenericArguments().Select(NameWithGenerics).ToList();
return $"newName<string.Join(",", list)>";
现在用这个测试:
Console.WriteLine(WhatIsMyType<IEnumerable<string>>());
Console.WriteLine(WhatIsMyType<List<int>>());
Console.WriteLine(WhatIsMyType<IList<int>>());
Console.WriteLine(WhatIsMyType<List<ContentBlob>>());
Console.WriteLine(WhatIsMyType<int[]>());
Console.WriteLine(WhatIsMyType<ContentBlob>());
Console.WriteLine(WhatIsMyType<Dictionary<string, Dictionary<int, int>>>());
你会得到
IEnumerable<String>
List<Int32>
IList<Int32>
List<ContentBlob>
Int32[]
ContentBlob
Dictionary<String,Dictionary<Int32,Int32>>
【讨论】:
以上是关于在 C# 中测试对象是不是属于泛型类型的主要内容,如果未能解决你的问题,请参考以下文章