C# - 引用动态生成程序集中的类型

17
我正在尝试弄清楚一个问题:当您动态生成程序集时,是否有可能引用先前动态生成的程序集中的类型。
例如:
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;

CodeDomProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();

parameters.GenerateInMemory = true;

CompilerResults results = provider.CompileAssemblyFromSource(parameters, @"
namespace Dynamic
{
    public class A
    {
    }
}
");

Assembly assem = results.CompiledAssembly;

CodeDomProvider provider2 = new CSharpCodeProvider();
CompilerParameters parameters2 = new CompilerParameters();

parameters2.ReferencedAssemblies.Add(assem.FullName);
parameters2.GenerateInMemory = true;

CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters2, @"
namespace Dynamic
{
    public class B : A
    {
    }
}
");

if (results2.Errors.HasErrors)
{
    foreach (CompilerError error in results2.Errors)
    {
        Console.WriteLine(error.ErrorText);
    }
}
else
{
    Assembly assem2 = results2.CompiledAssembly;
}

这段代码在控制台上输出以下内容:类型或命名空间名“A”未找到(您是否缺少 using 指令或程序集引用?)

我已经尝试了很多种方式,但似乎都没有起作用。我有些遗漏了吗?这真的可能吗?

编辑:修复代码中的错误会出现以下错误:找不到元数据文件“l0livsmn, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”

编辑2:稍微离题一点,但将GenerateInMemory更改为false,并执行parameters2.ReferencedAssemblies.Add(assem.Location);会使其编译正确,但我非常希望引用直接在内存中的程序集而不是输出临时文件。

2个回答

4
我认为在IT技术领域,

CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters, @"
namespace Dynamic
{
    public class B : A
    {
    }
}
");

您需要传递parameters2,而不是parameters

我找到了实现的方法,您不需要在内存中编译第一个,如果您不这样做,它会在您的临时目录中为此程序集创建一个dll文件,同时,在您的调用中

ReferencedAssemblies.Add() 

您不需要传递程序集名称,只需传递程序集路径即可。请看以下代码,它应该可以完美地运行:

        CodeDomProvider provider = new CSharpCodeProvider();
        CompilerParameters parameters = new CompilerParameters();            

        CompilerResults results = provider.CompileAssemblyFromSource(parameters, @"
            namespace Dynamic
            {
                public class A
                {
                }
            }
            ");

        Assembly assem = results.CompiledAssembly;

        CodeDomProvider provider2 = new CSharpCodeProvider();
        CompilerParameters parameters2 = new CompilerParameters();

        parameters2.ReferencedAssemblies.Add(assem.Location);
        parameters2.GenerateInMemory = true;

        CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters2, @"
            namespace Dynamic
            {
                public class B : A
                {
                }
            }
            ");

        if (results2.Errors.HasErrors)
        {
            foreach (CompilerError error in results2.Errors)
            {
                Console.WriteLine(error.ErrorText);
            }
        }
        else
        {
            Assembly assem2 = results2.CompiledAssembly;
        }

请看我的第二次编辑。我认为我们大约在同一时间解决了这个问题。如果可能的话,我仍然希望能够引用内存中的程序集。 - Ashley
看起来源代码已经运行并创建了第二个程序集。但是,如果您尝试加载驻留在第二个程序集中的类型(使用assem2.GetTypes()),则会收到ReflectionTypeLoadException异常。 - mehdi.loa
在第一次编译中,输出的 DLL 存储在临时文件夹中。为了使用它,您必须将其保存在应用程序目录中或添加搜索路径,如 https://dev59.com/vXM_5IYBdhLWcg3wcSx_ 中所述。 - mehdi.loa

2

MSDN指出,您可以:

类型引用的限制

程序集可以引用另一个程序集中定义的类型。临时动态程序集可以安全地引用在另一个临时动态程序集、可持久化动态程序集或静态程序集中定义的类型。然而,公共语言运行时不允许可持久化动态模块引用在临时动态模块中定义的类型。这是因为当保存到磁盘并加载后,运行时无法解析对在临时动态模块中定义的类型的引用。


3
现在的问题是,“我如何引用内存中的瞬态动态程序集?” - Ashley
我想知道:程序集是在内存中创建的,但它是否默认添加到ApplicationDomain中?还是需要自己加载?或者调用AppDomain.DefineDynamicAssembly方法? - Paul Williams
嗯,这是一个很好的问题。我试着玩了一会儿,动态生成的汇编代码肯定被加载了。 - Ashley
1
我也遇到了类似的问题!在我的代码中,我无法定义assem.Location。所有东西都在内存中加载和运行。我该怎么办?调试器显示它不是被赋值的属性。 - Latency

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接