使用Emit反射建立运行时模型
做这个功能目的是对旧项目代码分析管理,代码规划。
如果重头开发,统一一个框架小框架搞,人、时间到位都不是问题。但是旧应用系统优化,项目更新,就几个人开发加维护,接口层越多,bll层越来越厚,人来人往留下一堆代码,怎么管理呢?我现在方法是:看,仔细看,再仔细看,改,仔细改,再仔细改。一般出问题了,结合数据库,基本可以解决。如果重新搞,还得熟悉原来的代码,再搬进新的项目,费时费力。有没有一种方式最好不用写代码,做个配置界面,将业务SQL和逻辑用工作流的方式以字符串(JSon、描述对象模型(这玩意我自定义了一个对象来描述各类关系,下次讲))的形式先保存起来,形成一个运行时编程环境,配置完善后通过字符串生成自己喜欢的框架呢?找了好久没找到,就自己写个。
要解决不要写代码,那么所有层的Model(实体、DTO、其他业务模型)肯定要用运行时模型,传输统一用字符串,哪一层都能接受。这样一想,思路就有了。这里的所有模型只做三个事情:实例化、输入和输出。输入为object或者json,输出为object或者dynamic也可以是JSon。代码做了简单的封装。直接上代码:
动态生成帮助类:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Reflection.Emit; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace MagicModel 10 { 11 public abstract class EmitHelper 12 { 13 14 private static AssemblyName assmblyname; 15 private static string DllName; 16 private static AssemblyBuilder assemblybuilder; 17 private static ModuleBuilder modulebuilder; 18 private static TypeBuilder typebuilder; 19 private static Type _dymaticType; 20 21 public static Type DymaticType 22 { 23 get 24 { 25 return _dymaticType; 26 } 27 28 //set 29 //{ 30 // dymaticType = value; 31 //} 32 } 33 34 public static void Create(string dllname) 35 { 36 DllName = dllname; 37 assmblyname = new AssemblyName(DllName); 38 ///2程序集生成器 39 assemblybuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assmblyname, AssemblyBuilderAccess.RunAndSave); 40 41 // For a single-module assembly, the module name is usually 42 // the assembly name plus an extension. 43 ////3动态创建模块 44 modulebuilder = assemblybuilder.DefineDynamicModule(assmblyname.Name, assmblyname.Name + ".dll"); 45 } 46 public static void CreateClass(string NsClassName) 47 { 48 typebuilder = modulebuilder.DefineType(NsClassName, TypeAttributes.Public); 49 } 50 public static void CreateMember(string MemberName, Type memberType) 51 { 52 FieldBuilder fbNumber = typebuilder.DefineField( 53 "m_" + MemberName, 54 memberType, 55 FieldAttributes.Private); 56 57 58 PropertyBuilder pbNumber = typebuilder.DefineProperty( 59 MemberName, 60 System.Reflection.PropertyAttributes.HasDefault, 61 memberType, 62 null); 63 64 65 MethodAttributes getSetAttr = MethodAttributes.Public | 66 MethodAttributes.SpecialName | MethodAttributes.HideBySig; 67 68 69 MethodBuilder mbNumberGetAccessor = typebuilder.DefineMethod( 70 "get_" + MemberName, 71 getSetAttr, 72 memberType, 73 Type.EmptyTypes); 74 75 ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator(); 76 77 numberGetIL.Emit(OpCodes.Ldarg_0); 78 numberGetIL.Emit(OpCodes.Ldfld, fbNumber); 79 numberGetIL.Emit(OpCodes.Ret); 80 81 // Define the "set" accessor method for Number, which has no return 82 // type and takes one argument of type int (Int32). 83 MethodBuilder mbNumberSetAccessor = typebuilder.DefineMethod( 84 "set_" + MemberName, 85 getSetAttr, 86 null, 87 new Type[] { memberType }); 88 89 ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator(); 90 // Load the instance and then the numeric argument, then store the 91 // argument in the field. 92 numberSetIL.Emit(OpCodes.Ldarg_0); 93 numberSetIL.Emit(OpCodes.Ldarg_1); 94 numberSetIL.Emit(OpCodes.Stfld, fbNumber); 95 numberSetIL.Emit(OpCodes.Ret); 96 97 // Last, map the "get" and "set" accessor methods to the 98 // PropertyBuilder. The property is now complete. 99 pbNumber.SetGetMethod(mbNumberGetAccessor); 100 pbNumber.SetSetMethod(mbNumberSetAccessor); 101 ///最重要的是你最后要创建类型 102 103 } 104 public static Type SaveClass() 105 { 106 _dymaticType = typebuilder.CreateType(); 107 return DymaticType; 108 } 109 public static void Save() 110 { 111 assemblybuilder.Save(assmblyname.Name + ".dll"); 112 } 113 ///// <summary> 114 ///// 创建一个实体类并保存生成类型 115 ///// </summary> 116 ///// <param name="NsClassName"></param> 117 ///// <param name="propertys"></param> 118 //public void Execute(string NsClassName, Dictionary<string, Type> propertys) 119 //{ 120 121 // CreateClass(NsClassName); 122 // foreach (var item in propertys) 123 // { 124 // CreateMember(item.Key, item.Value); 125 // } 126 // SaveClass(); 127 // Save(); 128 //} 129 130 //public void Execute(List<M_DefineClass> _classes) { 131 132 // foreach (M_DefineClass _class in _classes) 133 // { 134 // CreateClass(_class.NsClassName); 135 // foreach (var prop in _class.Props) 136 // { 137 // CreateMember(prop.MemberName, prop.MemberType); 138 // } 139 // SaveClass(); 140 // } 141 142 //} 143 144 //public void Test(string dllname, string NsClassName, string MemberName, Type memberType) 145 //{ 146 // //1设置程序集名称 147 // assmblyname = new AssemblyName(dllname); 148 // ///2程序集生成器 149 // assemblybuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assmblyname, AssemblyBuilderAccess.RunAndSave); 150 // 3动态创建模块 151 // modulebuilder = assemblybuilder.DefineDynamicModule(assmblyname.Name, assmblyname.Name + ".dll"); 152 // ///4.创建类 153 // typebuilder = modulebuilder.DefineType(NsClassName, TypeAttributes.Public); 154 // ///5.创建私有字段 155 // FieldBuilder fbNumber = typebuilder.DefineField( 156 // "m_" + MemberName, 157 // memberType, 158 // FieldAttributes.Private); 159 160 // ///6.创建共有属性 161 // PropertyBuilder pbNumber = typebuilder.DefineProperty( 162 // MemberName, 163 // System.Reflection.PropertyAttributes.HasDefault, 164 // memberType, 165 // null); 166 167 168 // MethodAttributes getSetAttr = MethodAttributes.Public | 169 // MethodAttributes.SpecialName | MethodAttributes.HideBySig; 170 171 172 // MethodBuilder mbNumberGetAccessor = typebuilder.DefineMethod( 173 // "get_" + MemberName, 174 // getSetAttr, 175 // memberType, 176 // Type.EmptyTypes); 177 178 // ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator(); 179 180 // numberGetIL.Emit(OpCodes.Ldarg_0); 181 // numberGetIL.Emit(OpCodes.Ldfld, fbNumber); 182 // numberGetIL.Emit(OpCodes.Ret); 183 184 // // Define the "set" accessor method for Number, which has no return 185 // // type and takes one argument of type int (Int32). 186 // MethodBuilder mbNumberSetAccessor = typebuilder.DefineMethod( 187 // "set_" + MemberName, 188 // getSetAttr, 189 // null, 190 // new Type[] { typeof(int) }); 191 192 // ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator(); 193 // // Load the instance and then the numeric argument, then store the 194 // // argument in the field. 195 // numberSetIL.Emit(OpCodes.Ldarg_0); 196 // numberSetIL.Emit(OpCodes.Ldarg_1); 197 // numberSetIL.Emit(OpCodes.Stfld, fbNumber); 198 // numberSetIL.Emit(OpCodes.Ret); 199 200 // // Last, map the "get" and "set" accessor methods to the 201 // // PropertyBuilder. The property is now complete. 202 // pbNumber.SetGetMethod(mbNumberGetAccessor); 203 // pbNumber.SetSetMethod(mbNumberSetAccessor); 204 205 // ///最重要的是你最后要创建类型 206 // Type t = typebuilder.CreateType(); 207 // assemblybuilder.Save(assmblyname.Name + ".dll"); 208 209 //} 210 211 212 } 213 }
View Code
初始动态模型:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace MagicModel.BLL {public class DynamicInitBLL{static M_Base _m_base;/// <summary>/// 3.设置和获取,生成结果放入Base里/// </summary>public static M_Base M_Base{get{return _m_base;}set{_m_base = value;}}/// <summary>/// 初始化,实现步骤为三步/// </summary>/// <param name="m_base"></param>public DynamicInitBLL(M_Base m_base) {_m_base = m_base;EmitHelper.Create(_m_base._AssamblyName);}/// <summary>/// 1创建单个Class/// </summary>/// <param name="_class"></param>public void Exequte(M_DefineClass _class){EmitHelper.CreateClass(_class.NsClassName);foreach (var prop in _class.Props){EmitHelper.CreateMember(prop.MemberName, prop.MemberType);}_m_base.DymaticType.Add(new M_DymaticType() {TypeName=_class.NsClassName,DType= EmitHelper.SaveClass() });}/// <summary>/// 1创建多个Class/// </summary>/// <param name="_classes"></param>public void Exequte(List<M_DefineClass> _classes) {foreach (var item in _classes){Exequte(item);}}/// <summary>/// 2保存/// </summary>public void SaveAssembly() {EmitHelper.Save();}} }
View Code
模型赋值:
using MagicModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Reflection;namespace MagicModel.BLL {public class DynamicEmulateBLL{M_Base _m_base;public DynamicEmulateBLL(M_Base _mbase) {_m_base = _mbase;}public object ObjectEmulate(string nsclassName,object data) {Type _classType = _m_base.DymaticType.Where(a => a.TypeName == nsclassName).FirstOrDefault().DType;var obj = Activator.CreateInstance(_classType);foreach (PropertyInfo pi in _classType.GetProperties()){if (data.GetType().GetProperty(pi.Name)!=null){Console.WriteLine("有相同的值");pi.SetValue(obj, data.GetType().GetProperty(pi.Name).GetValue(data));} }return obj;}public object JsonEmulate(string nsclassName, string jsonstring) {Type _classType = _m_base.DymaticType.Where(a => a.TypeName == nsclassName).FirstOrDefault().DType;return Newtonsoft.Json.JsonConvert.DeserializeObject(jsonstring, _classType);}} }
View Code
交互模型:
using System; using System.Collections.Generic;namespace MagicModel {public class M_Base {public string _AssamblyName { get; set; }public List<M_DymaticType> DymaticType { get; set; } = new List<M_DymaticType>();}public class M_DymaticType{public string TypeName { get; set; }public Type DType { get; set; }}public class M_DefineClass{public string NsClassName { get; set; }public IEnumerable<M_ClassMember> Props { get; set; }}public class M_ClassMember {public string MemberName { get; set; }public Type MemberType { get; set; }}}
View Code
下面来测试下效果,先定义10个类:
打开vs里面的cmd开发人员命令提示”,输入ildasm,然后把生成的dll拖进去,有了。
赋值检验:
有效果了
到了这一步,动态模型生成完成,它的调用位置不仅限于运行时代码,也可以在其他环境中使用了。
疑问:
1.运行时环境下处理引用问题是个麻烦事,所以干脆静态一个AssemblyName,项目间交叉引用该怎么解决?
2.我开始用Assembly去取dll,发现两个问题。1,交叉引用出问题。2,赋值取值出问题。
3.这个RunAndSave参数直接加载进来了,所以就在这上面static保存在内存等待以后调用,有没有更好的方法调用?或者说我生成的dll文件想什么时候用什么时候用,在哪里用都由我决定。
以上资料全参考msdn。
模型层可以存库,做生成对比,做db对比等等,后面再优化!
转载于:https://www.cnblogs.com/coolbader/p/7959650.html
使用Emit反射建立运行时模型相关推荐
- 使用Emit反射建立运行时实体模型
做这个功能目的是对旧项目代码分析管理,代码规划. 如果重头开发,统一一个框架小框架搞,人.时间到位都不是问题.但是旧应用系统优化,项目更新,就几个人开发加维护,接口层越多,bll层越来越厚,人来人往留 ...
- jvm优化_镜像镜像–使用反射在运行时查看JVM内部
jvm优化 开发人员:Takipi会告诉您何时新代码在生产中中断–了解更多 我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射. 它是Java和Scala编程的主要方面,它使我们使用的库 ...
- jvm 内存镜像_镜像镜像–使用反射在运行时查看JVM内部
jvm 内存镜像 开发人员:Takipi会告诉您何时新代码在生产中中断– 了解更多 我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射. 它是Java和Scala编程的主要方面,它使我们 ...
- 镜像镜像–使用反射在运行时查看JVM内部
开发人员:Takipi会告诉您何时新代码在生产中中断– 了解更多 我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射. 它是Java和Scala编程的主要方面,它使我们使用的库可以与我们 ...
- Java反射运行时_java反射获得运行时属性的值
运行时动态获得属性的值(通过方法获得): Method[] methods = cls.getDeclaredMethods(); for (Method method : methods) { if ...
- 通过反射--操作运行时类中的指定的属性/方法
操作运行时类中的指定的属性: 1.getDeclaredField(String fieldName):获取运行类中指定变量名的属性: 2.保证当前属性时可访问的 : 属性.setAccessible ...
- Java基础知识点__获取运行时类的完整结构
通过反射获取运行时类的完整结构 Field,method,Construuuctor,Superclass,Interface,Annotation 实现的全部接口 继承的父类 全部的构造器 全部的构 ...
- @JVM内存模型(运行时数据区)
前言 说到Java内存区域,可能很多人第一反应是"堆栈".首先堆栈不是一个概念,而是两个概念,堆和栈是两块不同的内存区域,简单理解的话,堆是用来存放对象而栈是用来执行程序的.对于J ...
- JDK1.8-Java虚拟机运行时数据区域和HotSpot虚拟机的内存模型
2019独角兽企业重金招聘Python工程师标准>>> 官方文档规定的运行时数据区域 官方文档中规定的运行时数据区一共就几块: PC计数器, 虚拟机栈, 本地方法栈, 堆区, 方法区 ...
- JVM 内存模型:运行时常量池
1. 前言 最近研究Java基础知识.发现Java运行时常量池和String字符串有些一些细节的地方,值得我们注意的地方,最为一个Java开发人员对于这种java基本特性和JVM虚拟机的内存模型我们需 ...
最新文章
- hadoop实战二 单机部署2
- 电子书推荐--《Python灰帽子》,python黑客编程
- Python入门学习笔记11(静态方法、类方法与属性方法)
- 有一种叫“蒸汽波”豪横的平面设计手法
- 最长上升子序列LIS 动态规划 二分查找算法
- 类似pyinstaller_pyinstaller安装与使用——那些我踩过的坑
- nginx php mysql zend_性能测试基本功 - 手动配置nginx+php-cgi+zend+mysql
- 如何用Java实现进度条
- 计算机无法识别荣耀9,华为荣耀9连接不上电脑端华为手机助手怎么处理?
- CT图像去除金属伪影-MATLAB实现
- 统计检验方法 大全,t -test 检验,Anova 检验,卡方检验,Kolmogorov–Smirnov 检验
- 力扣刷题(347. 前 K 个高频元素)快速排序
- iPad播放网页视频(h5 video)失败的处理方法(Django网站)
- 有时候可用 UIWebView 代替 UITextView,解决行间距问题
- mysql sus bench_susbench性能测试工具
- ChinaSkills-高职组网络系统管理大赛-WinSer 2019 互联网网卡检测服务笔记
- QQ强制加好友链接,对方不同意我也加
- 双系统安装红旗linux,红旗LINUX怎么安装成双系统?
- 【点云系列】基于图结构的点云快速重采样 翻译
- Ventoy - 免格式化!超简单的『多合一』系统启动盘制作神器 (开源免费,多平台支持)...
热门文章
- 邮件服务器搬家,企业邮箱怎么“搬家”
- 访问HDFS报错:org.apache.hadoop.security.AccessControlException: Permission denied
- Ubuntu16.x服务器 安装 Java,Elasticsearch5.4.X,中文分词,同义词,Logstash5.4.X 日志搜集
- Win 10 下载与安装 Oracle 12c 详细图解 与 Oracle 12c 卸载
- Java 设计模式 之 单例模式(Singleton)
- 小马哥-Java 微服务实践 - Spring Boot 系列-01Java 微服务实践 - Spring Boot 系列(一)初体验...
- 小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_6、SpringBoot2.xHTTP请求配置讲解...
- ultraedit激活
- windbg分析Kernel32.dll导出表
- objective-C语言:第一个OC程序