博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
4.1 反射工具
阅读量:5082 次
发布时间:2019-06-13

本文共 8223 字,大约阅读时间需要 27 分钟。

在编写开发框架的时候,经常会使用反射。反射的作用主要是动态创建类型的实例,或者获取对象类型并动态调用方法、属性、字段等。

我们在以前的.net framework框架中,反射工具包含了许多方法,但是在.net core中由于appdomain等变化的原因,许多方法已不再使用。我只将重反射工具类(ReflectionHelper)重要的几个方法说明一下。

在框架编写过程中,我们会遇到这样的需求:找出应用所用到的所有程序集和类,然后进行下一步的处理。

例如,我们有一个通用控件类BaseControl,各种富文本编辑器控件(RichText)、表格控件(Table)、分页控件(Paganitation)等都继承于通用控件类BaseControl。甚至CMS这个项目的评论(Comment)等控件也会继承该通用控件类BaseControl。我们需求是要做一个下拉列表,列出所有的控件。因为各个子控件会分散在不同的程序集中,评论控件就在CMS程序集中,这样我们必然会搜索当前应用中的所有程序集,从中找出所有继承于BaseControl的控件子类。这就是控件的列表。(如果我懒病不发作,能够写的够久的话,自定义表单、自定义查询等技术点可以看到这个需求。)

下面的方法是找到所有的应用程序集:

1         private static IEnumerable
GetAssemblies() 2 { 3 List
assemblies = new List
(); 4 5 //以下2行,总是认为所有的个人程序集都依赖于core 6 Type type = typeof(ReflectionHelper); 7 8 var libs = DependencyContext.Default.CompileLibraries; 9 foreach (CompilationLibrary lib in libs)10 {11 //if (lib.Name.StartsWith("Microsoft") || lib.Name.StartsWith("System") || lib.Name.Contains(".System.") || lib.Name.StartsWith("NuGet") || lib.Name.StartsWith("AutoMapper")) continue;12 if (lib.Serviceable) continue;13 if (lib.Type == "package") continue;14 15 var assembly = Assembly.Load(new AssemblyName(lib.Name));16 assemblies.Add(assembly);17 18 //以下,总是认为所有的个人程序集都依赖于core19 20 ////过滤掉“动态生成的”21 //if (assembly.IsDynamic) continue;22 23 //if (assembly.FullName == type.AssemblyQualifiedName.Replace(type.FullName + ", ", ""))24 //{25 // assemblies.Add(assembly);26 // continue;27 //}28 29 //if (assembly.GetReferencedAssemblies().Any(ass => ass.FullName == type.AssemblyQualifiedName.Replace(type.FullName + ", ", "")))30 //{31 // assemblies.Add(assembly);32 //}33 }34 35 return assemblies;36 }

此处有个假设,第6行Type type = typeof(ReflectionHelper)。其中ReflectionHelper是核心应用程序集中的一个静态类,而核心应用程序集假设会被所有的应用程序集所引用。如果该假设不成立,需要将19-22行的注释去掉,针对每个找到的程序集获取所有引用的程序集。

if (lib.Serviceable) continue;和if (lib.Type == "package") continue; 这两行的意思是排除所有的系统程序集、Nuget下载包,减少搜索范围,提高效率。(这2行暂未最终确认。)

通过上面的程序,我们就可以从应用中找出所有的程序集。下一步从这些程序集中获取所有继承于BaseControl的控件子类。因为控件子类继承于BaseControl,因此子类所在的应用程序集必然引用BaseControl的应用程序集。从父类获取所有子类的方法如下:

1         #region 类型搜索 2         ///  3         /// 获取子类型 4         ///  5         /// 父类型 6         /// 
7 public static IEnumerable
GetSubTypes(Type type) 8 { 9 var assemblies = _Assemblies.Where(a =>10 {11 Assembly assembly = type.GetTypeInfo().Assembly;12 //基类所在程序集或依赖于基类的其他程序集13 return a.FullName == assembly.FullName || a.GetReferencedAssemblies().Any(ra => ra.FullName == assembly.FullName);14 });15 16 TypeInfo typeInfo = type.GetTypeInfo();17 18 return assemblies.SelectMany(a =>19 {20 return a.GetTypes().Where(t =>21 {22 if (type == t)23 {24 return false;25 }26 27 TypeInfo tInfo = t.GetTypeInfo();28 29 if (tInfo.IsAbstract || !tInfo.IsClass || !tInfo.IsPublic)30 {31 return false;32 }33 34 if (typeInfo.IsGenericTypeDefinition)35 {36 return type.IsAssignableFromGenericType(t);37 }38 39 return type.IsAssignableFrom(t);40 });41 });42 }43 44 ///
45 /// 获取子类型46 /// 47 ///
父类型
48 ///
49 public static IEnumerable
GetSubTypes
()50 {51 return GetSubTypes(typeof(T));52 }53 #endregion

其中_Assemblies是从GetAssemblies()方法返回的结果。

这样就能够获取当前的子类列表IEnumerable<Type>。对于我们的需求,可以这样写ReflectionHelper.GetSubTypes<BaseControl>()。但是该方法的结果是IEnumerable<Type>,是Type的列表。我们如果用下拉列表展示,应该展示的是中文名称,总不能显示类似namespace.classname, assemblyname的样子吧,这样会被客户骂的。应该下拉出来的是中文名,例如富文本编辑器、文件上传、分页、自动完成等。

简单的做法是在BaseControl中增加一个抽象的Name属性,各个子类实现时override这个属性,标识该控件的中文名,倒是可以实现,不过在获取Name属性时,必须要实例化各个子类,天知道子类的构造函数有哪些参数。

我们的做法是建一个TypeNameAttribute,标识在各个子控件类上。具体实现如下:

1     ///   2     /// 子类中,甚至TypeName,包括中英文及属性,以便反射使用  3     ///   4     [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]  5     public class TypeNameAttribute : Attribute  6     {  7         private string _Code, _Name, _Description;  8         ///   9         /// 英文 10         ///  11         public string Code 12         { 13             get 14             { 15                 return _Code; 16             } 17             set 18             { 19                 _Code = value; 20             } 21         } 22         ///  23         /// 中文 24         ///  25         public string Name 26         { 27             get 28             { 29                 return _Name; 30             } 31             set 32             { 33                 _Name = value; 34             } 35         } 36         ///  37         /// 描述 38         ///  39         public string Description 40         { 41             get 42             { 43                 return _Description; 44             } 45             set 46             { 47                 _Description = value; 48             } 49         } 50         ///  51         /// 构造函数 52         ///  53         /// 英文 54         /// 中文 55         /// 描述 56         public TypeNameAttribute(string code, string name, string description) 57         { 58             this._Code = code; 59             this._Name = name; 60             this._Description = description; 61         } 62  63         ///  64         /// 构造函数 65         ///  66         /// 英文 67         /// 中文 68         public TypeNameAttribute(string code, string name) : this(code, name, string.Empty) 69         { 70         } 71     } 72  73     ///  74     /// TypeName的工具类 75     ///  76     public static class TypeNameHelper 77     { 78         public static ConcurrentDictionary
> list = new ConcurrentDictionary
>(); 79 80 public static TypeNameHelperInfo GetTypeNameHelperInfo
(string code) 81 { 82 List
list = GetTypeNameHelperList
(); 83 84 return list.SingleOrDefault(info => info.Code == code); 85 } 86 87 ///
88 /// 根据基类,获取所有子类的TypeName 89 /// 90 ///
基类型
91 ///
子类的TypeName信息
92 public static List
GetTypeNameHelperList
() 93 { 94 if (list.ContainsKey(typeof(T))) 95 { 96 return list[typeof(T)]; 97 } 98 99 List
result = new List
();100 101 IEnumerable
typeList = ReflectionHelper.GetSubTypes
();102 103 foreach (Type type in typeList)104 {105 try106 {107 TypeNameAttribute attribute = ReflectionHelper.GetCustomAttribute
(type);108 result.Add(new TypeNameHelperInfo()109 {110 Code = attribute.Code,111 Name = attribute.Name,112 Description = attribute.Description,113 Type = type114 });115 }116 catch117 {118 }119 }120 121 list[typeof(T)] = result;122 123 return result;124 }125 }126 127 ///
128 /// TypeName的信息类129 /// 130 public class TypeNameHelperInfo131 {132 ///
133 /// 英文134 /// 135 public string Code { get; set; }136 ///
137 /// 中文138 /// 139 public string Name { get; set; }140 ///
141 /// 描述142 /// 143 public string Description { get; set; }144 ///
145 /// 类型146 /// 147 public Type Type { get; set; }148 }

例如自动完成控件就可以如下写法:

 

1     /// 2     /// 自动填充下拉框控件3     /// 4     [TypeName("AutoComplete", "自动填充下拉框")]5     public class AutoComplete : BaseControl6     {7     ...8     }

 最终就可以通过TypeNameHelper.GetTypeNameHelperList<BaseControl>()就可以获取所有的控件子类,子类列表存放在List<TypeNameHelperInfo>,绑定到select标签即可

 

转载于:https://www.cnblogs.com/BenDan2002/p/5996724.html

你可能感兴趣的文章
故障转移
查看>>
清空dataset中的某行某列的数据
查看>>
盒模型
查看>>
js中闭包和作用域
查看>>
关键词提取
查看>>
装饰器,迭代器与生成器
查看>>
endpoint 理解-1
查看>>
Lambad表达式树(转)
查看>>
15 SharePreference
查看>>
24点
查看>>
各种米的营养价值
查看>>
php 处理数字为金钱格式
查看>>
学习51单片机——秒表分享
查看>>
我画你猜(微信版--游戏说明)
查看>>
cssText的用法以及特点 转载至http://www.cnblogs.com/majingyi/p/6840818.html
查看>>
7款纯CSS3实现的炫酷动画应用
查看>>
sed结构分析 + awk结构分析
查看>>
MySQL安装+更换yum源+mysql密码忘记(2019更新)
查看>>
解决ubuntu10插入耳机还有外音的问题
查看>>
自用win10软件
查看>>