.NET 中提供了很多判断某个类型或实例是某个类的子类或某个接口的实现类的方法,然而这事情一旦牵扯到泛型就没那么省心了。

本文将提供判断泛型接口实现或泛型类型子类的方法。


.NET 中没有自带的方法

对于实例,.NET 中提供了这些方法来判断:

  1. if (instance is Foo || instance is IFoo)
  2. {
  3. }

对于类型,.NET 中提供了这些方法来判断:

  1. if (typeof(Foo).IsAssignableFrom(type) || typeof(IFoo).IsAssignableFrom(type))
  2. {
  3. }

或者,如果不用判断接口,只判断类型的话:

  1. if (type.IsSubClassOf(typeof(Foo)))
  2. {
  3. }

对于 typeof 关键字,不止可以写 typeof(Foo),还可以写 typeof(Foo<>)。这可以得到泛型版本的 Foo<T> 的类型。

不过,如果你试图拿这个泛型版本的 typeof(Foo<>) 执行上述所有判断,你会发现所有的 if 条件都会是 false

我们需要自己编写方法

typeof(Foo<>)typeof(Foo<SomeClass>) 之间的关系就是 GetGenericTypeDefinition 函数带来的关系。

所以我们可以充分利用这一点完成泛型类型的判断。

比如,我们要判断接口:

  1. public static bool HasImplementedRawGeneric(this Type type, Type generic)
  2. {
  3. // 遍历类型实现的所有接口,判断是否存在某个接口是泛型,且是参数中指定的原始泛型的实例。
  4. return type.GetInterfaces().Any(x => generic == (x.IsGenericType ? x.GetGenericTypeDefinition() : x));
  5. }

而如果需要判断类型,那么就需要遍历此类的基类了:

  1. public static bool IsSubClassOfRawGeneric([NotNull] this Type type, [NotNull] Type generic)
  2. {
  3. if (type == null) throw new ArgumentNullException(nameof(type));
  4. if (generic == null) throw new ArgumentNullException(nameof(generic));
  5. while (type != null && type != typeof(object))
  6. {
  7. isTheRawGenericType = IsTheRawGenericType(type);
  8. if (isTheRawGenericType) return true;
  9. type = type.BaseType;
  10. }
  11. return false;
  12. bool IsTheRawGenericType(Type test)
  13. => generic == (test.IsGenericType ? test.GetGenericTypeDefinition() : test);
  14. }

于是,我们可以把这两个方法合成一个,用于实现类似 IsAssignableFrom 的效果,不过这回将支持原始接口(也就是 typeof(Foo<>))。

  1. /// <summary>
  2. /// 判断指定的类型 <paramref name="type"/> 是否是指定泛型类型的子类型,或实现了指定泛型接口。
  3. /// </summary>
  4. /// <param name="type">需要测试的类型。</param>
  5. /// <param name="generic">泛型接口类型,传入 typeof(IXxx&lt;&gt;)</param>
  6. /// <returns>如果是泛型接口的子类型,则返回 true,否则返回 false。</returns>
  7. public static bool HasImplementedRawGeneric([NotNull] this Type type, [NotNull] Type generic)
  8. {
  9. if (type == null) throw new ArgumentNullException(nameof(type));
  10. if (generic == null) throw new ArgumentNullException(nameof(generic));
  11. // 测试接口。
  12. var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
  13. if (isTheRawGenericType) return true;
  14. // 测试类型。
  15. while (type != null && type != typeof(object))
  16. {
  17. isTheRawGenericType = IsTheRawGenericType(type);
  18. if (isTheRawGenericType) return true;
  19. type = type.BaseType;
  20. }
  21. // 没有找到任何匹配的接口或类型。
  22. return false;
  23. // 测试某个类型是否是指定的原始接口。
  24. bool IsTheRawGenericType(Type test)
  25. => generic == (test.IsGenericType ? test.GetGenericTypeDefinition() : test);
  26. }

.NET/C# 判断某个类是否是泛型类型或泛型接口的子类型的更多相关文章

  1. C#判断一个类中有无"指定名称"的方法

    C#中可以通过反射分析元数据来解决这个问题,示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 2 ...

  2. iOS 判断一个类是否存在,NSStringFromClass 不用 import 就可以获取类

    Class myCls = NSClassFromString(@"Person"); NSString *str = NSStringFromClass(myCls); if ( ...

  3. c++ 动态判断基类指针指向的子类类型(typeid)

    我们在程序中定义了一个基类,该基类有n个子类,为了方便,我们经常定义一个基类的指针数组,数组中的每一项指向都指向一个子类,那么在程序中我们如何判断这些基类指针是指向哪个子类呢? 本文提供了两种方法 ( ...

  4. 在C#中判断某个类是否实现了某个接口

    有时我们需要判断某个类是否实现了某个接口(Interface),比如在使用反射机制(Reflection)来查找特定类型的时候. 简单来说,可以使用Type.IsAssignableFrom方法: t ...

  5. 判断网络类(获取mac) InternetCheck

    using System; using System.Collections.Generic; using System.Net.NetworkInformation; using System.Ru ...

  6. 【.Net】在C#中判断某个类是否实现了某个接口

    有时我们需要判断某个类是否实现了某个接口(Interface),比如在使用反射机制(Reflection)来查找特定类型的时候. 简单来说,可以使用Type.IsAssignableFrom方法: t ...

  7. 在动态sql的使用where时,if标签判断中,如果实体类中的某一个属性是String类型,那么就可以这样来判断连接语句:

    在动态sql的使用where时,if标签判断中,如果实体类中的某一个属性是String类型,那么就可以这样来判断连接语句: 如果是String类型的字符串进行判空的时候: <if test=&q ...

  8. 实体类相同属性间赋值与如何判断实体类中是否所有的字段都为null

    1,实体类相同属性间赋值 /// <summary> /// 将实体2的值动态赋值给实体1(名称一样的属性进行赋值) /// </summary> /// <param ...

  9. Java判断一个类里是否存在某个属性

    Java判断一个类里是否存在某个属性 测试pojo类,比方我有个User类 @Getter @Setter public class User { private Long id; private S ...

随机推荐

  1. Bootstrap单按钮的下拉菜单

    简介 把任意一个按钮放入 .btn-group 中,然后加入适当的菜单标签,就可以让按钮作为菜单的触发器了. 插件依赖 按钮式下拉菜单依赖下拉菜单插件 ,因此需要将此插件包含在你所使用的 Bootst ...

  2. animation CSS3动画总结

    最近一个小游戏项目用到了CSS3的动画属性,例如transition.transform.animation.经过三个星期,终于做完了,利用周末好好梳理总结一下. keyframes这个属性用来定义一 ...

  3. pyDay15

    内容来自廖雪峰的官方网站. 1.Python提供的sum()函数可以接受一个list并求和,请编写一个prod()函数,可以接受一个list并利用reduce()求积. from functools ...

  4. 实验五分析system_call中断处理过程

    一.实验要求: 1.使用gdb跟踪分析一个系统调用内核函数 2.根据本周所学知识分析系统调用的过程,从system_call开始到iret结束之间的整个过程,并画出简要准确的流程图 二.实验步骤: 1 ...

  5. labview学习之“创建数组”函数

    “创建数组”函数 一.位置:“函数”-“编程”-“数组”-“创建数组” 其图标为: 图1 图标 二.简介: “创建数组”函数有两种模式,一种是“连接模式”,一种是“添加模式”. 如需切换两种模式,可右 ...

  6. luogu p1101 单词方阵

    https://www.luogu.org/problem/show?pid=1101 很恶心的代码  就是八个方向都搜索 #include<bits/stdc++.h> using na ...

  7. POJ 1833 排序

    http://poj.org/problem?id=1833 题意: 给出一个排序,求出它之后的第k个排序. 思路: 排序原理: 1.如果全部为逆序时,说明已经全部排完了,此时回到1~n的排序. 2. ...

  8. vue 2.5.14以上版本render函数不支持返回字符串

    vue 2.5.14以上版本render函数不再支持直接返回字符串,必须返回数组或vnode节点,如果返回字符串的话,渲染为空.详情可见源码. function createFunctionalCom ...

  9. vs警告 当前源代码跟内置的版本不一致解决办法

    本文转载于:http://blog.csdn.net/bull521/article/details/51334464 vs警告 当前源代码跟内置的版本不一致解决办法 1.删除掉 我的文档/visua ...

  10. mfc "缺少函数标题(是否是老式的形式表)"的总结

    首先出现这种问题要定位到程序中出错的地方查看,如果没有问题就仔细看类的声明和定义.可能是对应类的后面没有加: 第二个原因是可能忘记了添加头文件 "stdafx",如果是这样可以加上 ...