【问题标题】:How can I use CodeDOM to create and load an assembly in an AppDomain?如何使用 CodeDOM 在 AppDomain 中创建和加载程序集?
【发布时间】:2010-08-18 14:07:20
【问题描述】:

我正在开发一个项目,该项目将使用 CodeDOM 创建一个评估用户定义表达式的类,为该类创建一个程序集并加载该程序集。由于可以有相当数量的用户定义的表达式,我想首先创建一个 AppDomain,在该 AppDomain 中为程序集执行 CodeDOM 创建/加载和执行,然后卸载 AppDomain。

我进行了相当多的搜索,发现了许多关于如何将现有程序集加载到 AppDomain 中的示例,但我似乎找不到一个向我展示如何从 within 中创建程序集的示例em> AppDomain。

此示例 (DynamicCode) 使用 CodeDOM 创建程序集,然后将其加载到 AppDomain 中,但是,作者正在将程序集生成到磁盘。我宁愿在内存中生成程序集,这样我就不必管理生成的程序集的清理。 (即使这确实在临时文件夹中创建了一个 .dll)。

谁能给我举个例子来说明如何做到这一点?

任何帮助将不胜感激。

我已经从我的代码中摘录了一些摘录,所以你们都可以感受一下我到目前为止的内容:

private string CreateSource()
{
    CodeCompileUnit codeUnit = new CodeCompileUnit();
    CodeNamespace codeNamespace = new CodeNamespace(Namespace);
    CodeTypeDeclaration codeClass = new CodeTypeDeclaration
    {
        Name = "ExpressionEvaluator",
        IsClass = true,
        TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed
    };

    codeNamespace.Types.Add(codeClass);
    codeUnit.Namespaces.Add(codeNamespace);

    AddMethods(codeClass);

    string result = GenerateSourceCode(codeUnit);

    return result.ToString();
}

private CompilerResults CompileSource(string source)
{
    using (CodeDomProvider provider = new CSharpCodeProvider())
    {
        CompilerParameters parameters = CreateCompilerParameters();
        CompilerResults result = CompileCode(provider, parameters, source);

        return result;
    }
}

private static CompilerParameters CreateCompilerParameters()
{
    CompilerParameters result = new CompilerParameters
    {
        CompilerOptions = "/target:library",
        GenerateExecutable = false,
        GenerateInMemory = true
    };

    result.ReferencedAssemblies.Add("System.dll");

    return result;
}

private object RunEvaluator(CompilerResults compilerResults)
{
    object result = null;
    Assembly assembly = compilerResults.CompiledAssembly;

    if (assembly != null)
    {
        string className = "ExpressionEvaluator";
        object instance = assembly.CreateInstance("Lab.ExpressionEvaluator");

        Module[] modules = assembly.GetModules(false);

        Type type = (from t in modules[0].GetTypes()
                     where t.Name == className
                     select t).FirstOrDefault();

        MethodInfo method = (from m in type.GetMethods()
                             where m.Name == "Evaluate"
                             select m).FirstOrDefault();

        result = method.Invoke(instance, null);
    }
    else
    {
        throw new Exception("Unable to load Evaluator assembly");
    }

    return result;
}

我相信这些代码 sn-ps 显示了我项目的基本功能。现在我需要做的就是将它包装在它自己的 AppDomain 中。

【问题讨论】:

    标签: .net appdomain codedom


    【解决方案1】:

    我在http://www.softwareinteractions.com/blog/2010/2/7/loading-and-unloading-net-assemblies.html 找到了我正在寻找的答案。他有一篇很好的文章,详细介绍了 AppDomain 的创建和将程序集作为插件加载。我按照他的示例创建了一个 AppDomain,为我的 ExpressionEvaluator 类工厂创建了一个代理,并成功调用它并接收结果。

    【讨论】:

    【解决方案2】:

    鸡和蛋的问题。您需要一个小引导程序程序集,您可以将其加载到新的 AppDomain 中。使用一个众所周知的类来加载 CodeDom 生成的程序集并使其运行。

    使用 GenerateInMemory 执行此操作毫无意义,您必须将其序列化到新的 AppDomain 中。这只是一堆开销,还不如从磁盘加载它,反正它就在那里。它已经在记忆中。文件系统缓存的内存。加载它会非常快,因为它实际上不需要从磁盘中读取。

    【讨论】:

      【解决方案3】:

      在定义dynamic assembly 时只需使用AssemblyBuilderAccess.Run http://msdn.microsoft.com/en-us/library/system.reflection.emit.assemblybuilderaccess.aspx

      动态程序集可以执行,但不能保存。

      【讨论】:

      • 我相信您将 Reflection.Emit 与 CodeDom 混淆了。
      • 谢谢乔尔。我正在研究动态程序集。
      【解决方案4】:

      CompilCode 方法从何而来?这似乎是最重要的部分,而您决定将其省略?

      【讨论】:

      • CompileCode 方法与问题没有密切关系,即如何生成源代码、创建程序集并在运行时将其加载到 AppDomain 中。我意识到我最初的问题可能不是对我的问题的完全准确描述,但随着我收到反馈并进行更多研究,它改进了问题的范围和定义。具体来说,我试图执行的操作顺序。已接受答案中的文章阐明了我需要采取的方法,并帮助我解决了我的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多