• 利用Refly和CodeDom实现代码的动态生成和动态编译


    CodeDom是.NET框架中比较强大也是比较难懂的对象模型,通过它可以实现.NET支持各种语言代码的动态生成及动态编译。我们先来看看CodeDom的定义:.NET Framework 中包含一个名为“代码文档对象模型”(CodeDOM) 的机制,该机制使编写源代码的程序的开发人员可以在运行时,根据表示所呈现代码的单一模型,用多种编程语言生成源代码。

    Refly则是国外一个开发者对CodeDom进行封装,目的是使得Codedom的实现更加方便易懂,和CodeDom的使用对比,代码更加简洁优雅,不过要了解整体的东西,也需要对CodeDOM进行详细的了解才能熟练应用。

    本人在研究学习Refly当中(详细可以参考http://www.codeproject.com/Articles/6283/Refly-makes-the-CodeDom-er-life-easier),对其中简单的应用有一些体会,做了一个使用Refly生成代码的例子进行测试,并使用CodeDOM进行动态编译。例子应该还算简单,用来说明Refly的工作机制应该还是足够的,同时也希望与大家探讨一下进一步的应用。

    生成类代码的代码如下所示:

                #region 生成代码

    //创建命名空间
    NamespaceDeclaration ns = new NamespaceDeclaration("Demo");
    ns.Imports.Add("System.Xml");
    ns.Imports.Add("System.IO");
    ns.Imports.Add("System.ComponentModel");
    ns.Imports.Add("System.Xml.Serialization");

    // 创建类定义
    ClassDeclaration user = ns.AddClass("User");
    //添加类说明
    user.Doc.Summary.AddText("测试用户类描述");
    user.Doc.Remarks.Add("para");
    user.Doc.Remarks.Into();
    user.Doc.Remarks.AddText("该类是使用Refly进行生成");
    user.Doc.Remarks.OutOf();

    // 添加字段
    FieldDeclaration name = user.AddField(typeof(string), "name");
    FieldDeclaration age = user.AddField(typeof(int), "age");

    // 添加构造函数(默认)
    user.AddConstructor();
    ConstructorDeclaration cstr = user.AddConstructor();
    // 添加构造函数(参数)
    ParameterDeclaration cstr_name = cstr.Signature.Parameters.Add(typeof(string), "name", true);

    cstr.Body.AddAssign(Expr.This.Field(name), Expr.Arg(cstr_name));

    // 添加属性Name
    PropertyDeclaration proName = user.AddProperty(name, true, true, false);
    proName.Doc.Summary.AddText("用户名称");
    //添加属性的Attribute
    AttributeDeclaration attr = proName.CustomAttributes.Add(typeof(XmlElementAttribute));
    attr.Arguments.Add("ElementName", Expr.Prim(proName.Name));

    // 添加属性Age
    PropertyDeclaration proAge = user.AddProperty(age, true, true, false);
    proName.Doc.Summary.AddText("用户年龄");

    //添加方法
    MethodDeclaration add = user.AddMethod("Add");
    add.Doc.Summary.AddText("添加用户内容");
    ParameterDeclaration pName = add.Signature.Parameters.Add(typeof(string), "name", true);
    add.Doc.AddParam(pName);
    ParameterDeclaration pAge = add.Signature.Parameters.Add(typeof(int), "age", true);
    add.Body.Add(Stm.Assign(Expr.This.Prop("Name"), Expr.Arg(pName)));
    add.Body.Add(Stm.Assign(Expr.This.Prop("Age"), Expr.Arg(pAge)));

    //添加方法2
    MethodDeclaration show = user.AddMethod("Show");
    show.Doc.Summary.AddText("输出用户名称");
    show.Body.Add(Expr.Snippet("Console").Method("WriteLine").Invoke(Expr.This.Prop("Name")));

    // 输出结果
    Refly.CodeDom.CodeGenerator gen = new Refly.CodeDom.CodeGenerator();
    gen.Provider = Refly.CodeDom.CodeGenerator.CsProvider;
    gen.GenerateCode(Application.StartupPath + "/CS", ns);

    #endregion

    编译代码好像Refly没有找到,所以用原始的CodeDOM的对象操作进行代码的动态编译,编译代码如下所示:

               #region 动态编译代码

    string file = string.Format("{0}\\CS\\Demo\\User.cs", Application.StartupPath);
    string code = FileUtil.FileToString(file);
    string output = string.Format("{0}\\CS\\Demo\\User.dll", Application.StartupPath);

    CSharpCodeProvider codeProvider = new CSharpCodeProvider();
    CompilerParameters parameters = new CompilerParameters();
    parameters.ReferencedAssemblies.Add("System.dll");
    parameters.ReferencedAssemblies.Add("System.Data.dll");
    parameters.ReferencedAssemblies.Add("System.Xml.dll");
    parameters.GenerateInMemory = false;
    parameters.TreatWarningsAsErrors = false;
    parameters.OutputAssembly = output; //设定输出文件名称路径

    //判断编译结果
    //CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);
    CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, file);
    if (results.Errors.HasErrors)
    {
    string errorMessage = "";
    errorMessage = results.Errors.Count.ToString() + " Errors:";
    for (int x = 0; x < results.Errors.Count; x++)
    {
    errorMessage = errorMessage + "\r\nLine: " +
    results.Errors[x].Line.ToString() + " - " + results.Errors[x].ErrorText;
    }
    MessageUtil.ShowError(errorMessage);
    }
    //string path = results.PathToAssembly;

    return results.Errors.Count == 0;

    #endregion

    代码编译了,我们使用的编译好的类也就可以了,使用操作代码如下所示,例子我使用反射,把生成的对象加载,并绑定到PropertyGrid控件中。

            private void btnTest_Click(object sender, EventArgs e)
    {
    GenerateCompile();

    string assemblyFile = string.Format("{0}\\CS\\Demo\\User.dll", Application.StartupPath);
    if (File.Exists(assemblyFile))
    {
    Assembly assObj = Assembly.LoadFile(assemblyFile);
    if (assObj != null)
    {
    object obj = assObj.CreateInstance("Demo.User");
    this.propertyGrid1.SelectedObject = obj;
    }
    }
    }

    最终例子运行的效果如下所示。

    其实最终生成的User类代码如下所示。

    // Generated by Refly
    namespace Demo
    {
    using System;
    using System.Xml;
    using System.IO;
    using System.ComponentModel;
    using System.Xml.Serialization;

    /// <summary>测试用户类描述</summary>
    /// <remarks>
    ///<para>该类是使用Refly进行生成</para>
    /// </remarks>
    public class User
    {

    private int _age;

    private string _name;

    public User()
    {
    }

    public User(string name)
    {
    this._name = name;
    }

    /// <summary>用户名称用户年龄</summary>
    [XmlElementAttribute(ElementName="Name")]
    public virtual string Name
    {
    get
    {
    return this._name;
    }
    set
    {
    this._name = value;
    }
    }

    public virtual int Age
    {
    get
    {
    return this._age;
    }
    set
    {
    this._age = value;
    }
    }

    /// <summary>添加用户内容</summary>
    /// <param name="name" />
    public virtual void Add(string name, int age)
    {
    this.Name = name;
    this.Age = age;
    }

    /// <summary>输出用户名称</summary>
    public virtual void Show()
    {
    Console.WriteLine(this.Name);
    }
    }
    }



    主要研究技术:代码生成工具、会员管理系统、客户关系管理软件、病人资料管理软件、Visio二次开发、酒店管理系统、仓库管理系统等共享软件开发
    专注于Winform开发框架/混合式开发框架Web开发框架Bootstrap开发框架微信门户开发框架的研究及应用
      转载请注明出处:
    撰写人:伍华聪  http://www.iqidi.com 
        
  • 相关阅读:
    jS Ajax 上传文件报错"Uncaught TypeError: Illegal invocation"
    layer实现关闭弹出层刷新父界面功能详解
    PHP开发APP接口简单签名全过程(二)实际测试
    PHP开发APP接口简单签名全过程(一)
    Laravel 避免 Trying to get property of non-object 错误的六种方法 [新增第六种 data_get]
    在PHP代码中将HTML代码原样输出的方式
    在使用 Laravel Eloquent 模型时,我们要判断取出的结果集是否为空,但我们发现直接使用 is_null 或 empty是无法判段它结果集是否为空的!!!
    使用layer的iframe层提交表单后,需要关闭当前的iframe层,然后刷新父页面的方法
    laravel中如何实现验证码验证及使用
    递归思想的由来
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/2426091.html
Copyright © 2020-2023  润新知