使用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对比等等,后面再优化!

 

 

 

 

    

posted on 2017-12-03 02:11  kloszhu  阅读(514)  评论(0编辑  收藏  举报

导航