动态编译程序与创建卸载程序域

==============================================动态编译程序思路

* 0,把C#以字符串的方式放在string对象里
     * 1,实例化一个C#编译器:CSharpCodeProvider
     * 2,创建编译器环境(并配置环境):CompilerParameters
     * 3,开始编译:ccp.CompileAssemblyFromSource(cp, abc);
     * 4,返回编译结果:CompilerResults
     * 【5,可以使用反射调用该程序集】

==============================================什么是程序域?

在.net技术之前,进程做为应用程序独立的边界,

.net体系结构中,应用程序有一个新的边界,就是程序域。可以合理分配对象在不同的程序域中,

可以对程序域进行卸载

==============================================程序域的作用

如果程序集是动态加载的,且需要在使用完后卸载程序集,应用程序域就非常有
用。 在主应用程序域中,不能删除已加载的程序集,但可以终止应用程序域,在该应
用程序域中载的所有程序集都会从内存中清除。

==============================================例子:

--------------------------------------CompileType.cs(枚举文件)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppDomainDemo
{
    public enum CompileType
    {
        Console,//控制台输出
        File//输出文件
    }
}

--------------------------------------CompileCode.cs(动态编译程序代码类)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using Microsoft.CSharp;//提供对 C# 代码生成器和代码编译器的实例的访问。
using System.CodeDom.Compiler;//用途是对所支持编程语言的源代码的生成和编译进行管理
namespace AppDomainDemo
{
    //MarshalByRefObject:跨域访问必须要继承此类
    public class CompileCode : MarshalByRefObject
    {
        public string CompileCodeGo(string input, CompileType ct, out bool IsError)
        {
            StringBuilder sb1 = new StringBuilder();
            sb1.Append("using System;");
            sb1.Append("using System.Windows.Forms;");
            sb1.Append("public class Program{public static void Main(string[] args){");
            StringBuilder sb2 = new StringBuilder();
            sb2.Append("}");
            sb2.Append("public void aa(){");
            string bottom = "}}";
            //编译器
            CSharpCodeProvider ccp = new CSharpCodeProvider();
            //编译参数配置
            CompilerParameters cp = new CompilerParameters();
            //编译结果
            CompilerResults cr;
            //控制台输出
            if (ct == CompileType.Console)
            {
                //设置是否在内存中生成输出
                cp.GenerateInMemory = true;
            }
            else//编译为可执行文件
            {
                //是否是可执行文件
                cp.GenerateExecutable = true;
                //配置输出文件路径
                cp.OutputAssembly = Directory.GetCurrentDirectory() + "/" + DateTime.Now.ToString("yyyyMMhhddmmss") + ".exe";
            }
            //引用程序集
            cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            
            //编译
            cr = ccp.CompileAssemblyFromSource(cp, sb1.ToString() + input + sb2.ToString() + input + bottom);
            if (cr.Errors.HasErrors)//编辑结果出现异常
            {
                IsError = true;
                string error = "";
                for (int i = 0; i < cr.Errors.Count; i++)
                {
                    error += string.Format("影响行数:{0},错误信息:{1}\r\n", cr.Errors[i].Line.ToString(), cr.Errors[i].ErrorText);
                }
                return error;
            }
            else
            {
                IsError = false;
                //用于接受控制台输出的信息
                StringWriter sw = new StringWriter();
                Console.SetOut(sw);
                //获取编译的程序集[反射]
                Assembly asb = cr.CompiledAssembly;
                //获取类
                Type t = asb.GetType("Program");
                //非静态方法需要实例化类
                object o = Activator.CreateInstance(t);
                //获取方法
                MethodInfo m = t.GetMethod("aa");
                //执行方法
                m.Invoke(o, null);
                //返回控制台输出的结果
                return sw.ToString();
            }

        }
    }
}

--------------------------------------AppDomainCode.cs(创建卸载程序域类)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AppDomainDemo
{
    public class AppDomainCode
    {
        public string AppDomainCodeGo(string input, CompileType ct, out bool IsError)
        {
            //创建程序域
            AppDomain app = AppDomain.CreateDomain("zhangdi");
            //创建制定类型的实例
            CompileCode cc = (CompileCode)app.CreateInstanceAndUnwrap("AppDomainDemo", "AppDomainDemo.CompileCode");
            
            string result= cc.CompileCodeGo(input, ct, out IsError);
            //卸载程序域
            AppDomain.Unload(app);
            return result;
        }
    }
}

--------------------------------------Form1.cs(窗体后台程序)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AppDomainDemo
{
    /*
     *************************************
     *代码不能为Console.ReadKey();
     *点击 点击我输出控制台 按钮【出现错误:调用的目标发生了异常】
     *这个错误我找了好几天,坑爹
     *************************************
     */
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        string str = "Console.WriteLine(\"aasdasd\");Console.ReadLine();";
        /// <summary>
        /// 点我输出控制台
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConsole_Click(object sender, EventArgs e)
        {
            AppDomainCode adc = new AppDomainCode();
            bool iserror;
            string result = adc.AppDomainCodeGo(str, CompileType.Console, out iserror);
            richTextBox1.Text = result;
        }
        /// <summary>
        /// 点我输出可执行文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnFile_Click(object sender, EventArgs e)
        {
            AppDomainCode adc = new AppDomainCode();
            bool iserror;
            string result = adc.AppDomainCodeGo(str, CompileType.File, out iserror);
            richTextBox1.Text = result;
        }

    }
}
时间: 2024-10-12 22:25:51

动态编译程序与创建卸载程序域的相关文章

VC++6.0 动态库的创建与调用(非MFC的dll)

非MFC动态库的创建... 一个lib.cpp,一个lib.h /*lib.h*/ #ifndef LIB_H #define LIB_H //声明add为dll的导出函数. extern "C" int _declspec(dllexport)add(int x,int y); #endif 也可以加上def文件 ; lib.def : 导出DLL函数 LIBRARY DllTestDef EXPORTS add @ 1 非MFc动态库的调用 1.静态调用 //静态的调用dll动态库

C/C++ (函数、变量和类)动态库的创建、导出和使用(图文+示例代码)

 一 Windows库 1引入库的原因: a.项目的复杂程度大 b.提高代码的利益利用率 2库的分类 2.1静态库: *.lib,不能被加载的程序,可以理解为目标程序的归档. 2.2动态库:*.dll,可以被应用程序加载的程序. 二 动态库 1动态库优点 1.1可以提供模块化的方式,方便协调开发(对于大项目,每个人写的东西编译为动态库,直接链接即可) 1.2对源代码保护 1.3减小可执行文件大小 1.4提高代码重用率 2动态库的基本使用方法 2.1动态库的创建 2.2加载动态库 2.3获取并

动态库的创建和调用

(一)动态链接库和静态链接库 静态链接库:lib中的函数不仅被连接,全部实现都被直接包含在最终生成的EXE文件中,只是实现是不可见的. 动态链接库:dll不必被包含在最终的EXE中,静态调用时仅把函数名或者变量名或者类名链接到EXE文件中,而这些东西的实体都只有在运行时才从动态库中导入到可执行文件中,动态调用的时候EXE文件执行时可以直接动态地引用和卸载DLL文件. 同时,静态链接库中不能再包含其他的动态链接库或静态库,而动态链接库中可以包含其他的动态或静态库. (二)回顾一下VC++支持的DL

使用AppDomain进行动态加载和卸载dll

加载dll最简单的写法 Assembly.Load("<dll路径>") 但这样写这个dll就被程序占用不可删除,即不可以卸载. 通过AppDomain加代理的方式进行加载则可以实现卸载,从而实现程序不被占用并被删除. 第一步,创建AssemblyProxy类 public class AssemblyProxy : MarshalByRefObject { private Assembly assembly; public void LoadAssembly(string

COCOS2DX学习之Box2d物理引擎使用之------动态物体的创建

1.创建一个物理世界 首先要引入一个头文件#include "Box2D\Box2D.h" 之后利用b2word创建一个对象,并且指定这个物理世界中的加速度方向. word = new b2World(b2Vec2(0,-10));                        //指定物理世界的加速度 最后还要重写一下update函数,这个函数在之前的计时器学习的时候已经说过,每一帧的变动都将自动执行这个函数.所以我们要通过这个函数来进行创建的物理世界的刷新. 2.创建一个运动的物体

《C语言中动态数组的创建及引用》

C语言中动态数组的创建及引用 动态数组是相对于静态数组而言的,静态数组的长度是预定义好的,在整个程序中,一旦给定了数组大小后就无法改变,,而动态数组则不然,它可以根据程序需要重新指定数组的大小.动态数组的内存空间是由堆动态分配的,通过执行代码为其分配储存空间,只有程序执行到分配语句时,才为其分配储存空间. 对于动态数组,其创建比静态数组更麻烦一些,使用完必须由程序员自己释放,否则将引起内存泄漏,但是其使用非常灵活,能根据程序需要动态分配大小,因此相对于静态数组来说,使用动态数组的自由度更大. 对

关于Emit中动态类型TypeBuilder创建类标记的一点思考

  利用TypeBuilder是可以动态创建一个类型,现在有个需求,动态生成一个dll,创建类型EmployeeEx,需要继承原dll里面的Employee类,并包含Employee类上的所有类标记.   网上有很多例子, //创建TypeBuilder. TypeBuilder myTypeBuilder = myModBuilder.DefineType(typeName, TypeAttributes.Public); myTypeBuilder.SetParent(type);   大概

一维动态数组和二维动态数组的创建和使用

#include<stdio.h> #include<malloc.h> void main(){ int *a,n=10,i; /* calloc()函数的原型是:(void *)calloc(unsigned n,unsigned size) calloc()函数用于向系统动态申请n个,每个占sizege字节的内存单元,函数返回值为所申请的内存空间首地址 malloc和calloc主要区别在于,当系统的内存只剩下一些非常小的碎片时,用calloc函数设计的动态数组的时间效率优于

使用反射和泛型,动态读取XML创建类实例并赋值

[狗刨学习网]unity极致学院,致力于打造业内unity3d培训.学习第一品牌. 前言: 最近小匹夫参与的游戏项目到了需要读取数据的阶段了,那么觉得自己业余时间也该实践下数据相关的内容.那么从哪入手呢?因为用的是Unity3d的游戏引擎,思来想去就选择了C#读取XML文件这个小功能.网上的例子倒也不少,但总是觉得缺点什么.比如读取xml文件之后该如何处理?看到的文章基本上都是手动创建一个目标类的实例,然后手动从读取的XML文件的内容中给刚才创建的目标类实例相关字段赋值.缺点什么呢?对嘞,感觉上