.net 如何使用CodeDOM在AppDomain中创建和加载程序集?

.net 如何使用CodeDOM在AppDomain中创建和加载程序集?,.net,appdomain,codedom,.net,Appdomain,Codedom,我正在从事一个项目,该项目将使用CodeDOM创建一个类,该类对用户定义的表达式求值,为该类创建一个程序集,并加载该程序集。由于可能有相当数量的用户定义表达式,我想首先创建一个AppDomain,在该AppDomain中为程序集执行CodeDOM创建/加载和执行,然后卸载AppDomain 我搜索了很多,找到了很多如何将现有程序集加载到AppDomain的示例,但似乎找不到一个示例演示如何从AppDomain中创建程序集 本例()使用CodeDOM创建一个程序集,然后将其加载到AppDomain

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

我搜索了很多,找到了很多如何将现有程序集加载到AppDomain的示例,但似乎找不到一个示例演示如何从AppDomain中创建程序集

本例()使用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;
}

我相信这些代码片段展示了我的项目的基本功能。现在,我需要做的就是将其包装到自己的AppDomain中。

只需使用
AssemblyBuilderAccess。定义

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


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


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

我找到了我想要的答案。他有一篇很好的文章,详细介绍了AppDomain的创建和作为插件加载程序集。我遵循他的示例,能够创建一个AppDomain,为我的ExpressionEvaluator类工厂创建一个代理,并成功地调用它并接收结果。

在所有这些中,
compileCode
方法从何而来?这似乎是最重要的部分,您决定将其忽略?

我相信您混淆了反射。使用CodeDom发射。谢谢Joel。我正在研究动态程序集。
CompileCode
方法与这个问题并不密切相关,这个问题是如何在运行时生成源代码、创建程序集并将其加载到
AppDomain
。我意识到我最初的问题可能并不是对我的问题的完全准确的描述,但随着我收到反馈并做了更多的研究,它细化了问题的范围和定义。具体来说,就是我试图执行的操作顺序。接受答案中的文章阐明了我需要采取的方法,并帮助我解决了问题。现在这是一个死链接。@David L: