使用Emit反射建立运行时实体模型
做這個功能目的是對舊項目代碼分析管理,代碼規劃。
如果重頭開發,統一一個框架小框架搞,人、時間到位都不是問題。但是舊應用系統優化,項目更新,就幾個人開發加維護,接口層越多,bll層越來越厚,人來人往留下一堆代碼,怎么管理呢?我現在方法是:看,仔細看,再仔細看,改,仔細改,再仔細改。一般出問題了,結合數據庫,基本可以解決。如果重新搞,還得熟悉原來的代碼,再搬進新的項目,費時費力。有沒有一種方式最好不用寫代碼,做個配置界面,將業務SQL和邏輯用工作流的方式以字符串(JSon、描述對象模型(這玩意我自定義了一個對象來描述各類關系,下次講))的形式先保存起來,形成一個運行時編程環境,配置完善后通過字符串生成自己喜歡的框架呢?找了好久沒找到,就自己寫個。
要解決不要寫代碼,那么所有層的Model(實體、DTO、其他業務模型)肯定要用運行時模型,傳輸統一用字符串,哪一層都能接受。這樣一想,思路就有了。這里的所有模型只做三個事情:實例化、輸入和輸出。輸入為object或者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/7959630.html
總結
以上是生活随笔為你收集整理的使用Emit反射建立运行时实体模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sqldeveloper 连接oracl
- 下一篇: 【例4-4】最小花费