测试对象是否为 C# 中的泛型类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/982487/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Testing if object is of generic type in C#
提问by Richbits
I would like to perform a test if an object is of a generic type. I've tried the following without success:
我想测试一个对象是否是泛型类型。我尝试了以下但没有成功:
public bool Test()
{
List<int> list = new List<int>();
return list.GetType() == typeof(List<>);
}
What am I doing wrong and how do I perform this test?
我做错了什么,我该如何进行这个测试?
采纳答案by Mehrdad Afshari
If you want to check if it's an instance of a generic type:
如果要检查它是否是泛型类型的实例:
return list.GetType().IsGenericType;
If you want to check if it's a generic List<T>
:
如果你想检查它是否是一个通用的List<T>
:
return list.GetType().GetGenericTypeDefinition() == typeof(List<>);
As Jon points out, this checks the exact type equivalence. Returning false
doesn't necessarily mean list is List<T>
returns false
(i.e. the object cannot be assigned to a List<T>
variable).
正如 Jon 指出的那样,这会检查确切的类型等效性。返回false
并不一定意味着list is List<T>
返回false
(即对象不能分配给List<T>
变量)。
回答by Stan R.
return list.GetType().IsGenericType;
回答by Jon Skeet
I assume that you don't just want to know if the type is generic, but if an object is an instance of a particular generic type, without knowing the type arguments.
我假设您不只是想知道类型是否是泛型,而是想知道对象是否是特定泛型类型的实例,而不知道类型参数。
It's not terribly simple, unfortunately. It's not too bad if the generic type is a class (as it is in this case) but it's harder for interfaces. Here's the code for a class:
不幸的是,这并不是非常简单。如果泛型类型是一个类(就像在这种情况下一样),那还不错,但是对于接口来说就更难了。这是一个类的代码:
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>
{
}
}
EDIT: As noted in comments, this may work for interfaces:
编辑:如评论中所述,这可能适用于接口:
foreach (var i in type.GetInterfaces())
{
if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
{
return true;
}
}
I have a sneaking suspicion there may be some awkward edge cases around this, but I can't find one it fails for right now.
我偷偷怀疑这可能有一些尴尬的边缘情况,但我现在找不到它失败的情况。
回答by David Desmaisons
You can use shorter code using dynamic althougth this may be slower than pure reflection:
您可以使用动态使用较短的代码,尽管这可能比纯反射慢:
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();
回答by Wiebe Tijsma
These are my two favorite extension methods that cover most edge cases of generic type checking:
这是我最喜欢的两个扩展方法,它们涵盖了泛型类型检查的大多数边缘情况:
Works with:
适用于:
- Multiple (generic) interfaces
- Multiple (generic) base classes
Has an overload that will 'out' the specific generic type if it returns true (see unit test for samples):
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; } }
- 多个(通用)接口
- 多个(通用)基类
有一个重载,如果它返回 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; } }
Here's a test to demonstrate the (basic) functionality:
这是一个演示(基本)功能的测试:
[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);
}