testing对象是C#中的genericstypes
我想执行一个testing,如果一个对象是一个genericstypes。 我已经尝试了以下没有成功:
public bool Test() { List<int> list = new List<int>(); return list.GetType() == typeof(List<>); }
我在做什么错了,我该如何执行这个testing?
如果你想检查它是否是一个genericstypes的实例:
return list.GetType().IsGenericType;
如果你想检查它是否是一个通用的List<T>
:
return list.GetType().GetGenericTypeDefinition() == typeof(List<>);
正如Jon指出的那样,这将检查确切的types等价性。 返回false
不一定意味着list is List<T>
返回false
(即对象不能被分配给List<T>
variables)。
我假设你不只是想知道types是否是generics的,但是如果一个对象是特定genericstypes的一个实例,而不知道types参数。
不幸的是,这不是非常简单。 如果generics是一个类(就像在这种情况下那样),但是接口更难。 这是一个类的代码:
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> { } }
编辑:正如评论中指出的,这可能适用于接口:
foreach (var i in type.GetInterfaces()) { if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType) { return true; } }
我有一个偷偷摸摸的怀疑,可能有一些尴尬边缘的情况下,但我找不到一个它现在失败。
你可以使用更短的代码使用dynamicalthougth这可能比纯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();
这些是我最喜欢的扩展方法,它涵盖了大多数通用types检查的边界情况:
适用于:
- 多个(通用)接口
- 多个(通用)基类
-
如果返回true,则会有一个“超出”具体genericstypes的重载(请参阅针对示例的unit testing):
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; } }
这是一个testing来演示(基本)function:
[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); }
return list.GetType().IsGenericType;