在运行时多次加载 Roslyn 编译的 DLL

Posted

技术标签:

【中文标题】在运行时多次加载 Roslyn 编译的 DLL【英文标题】:Load with Roslyn compiled DLL at runtime multiple times 【发布时间】:2016-05-10 06:17:53 【问题描述】:

目前我正在运行时编译和加载程序集。程序集始终包含相同的命名空间和类。当我这样做时 在同一个应用程序实例中多次,在创建程序集中的类的新实例时,总是会使用 最新 程序集吗?还是不能保证?

【问题讨论】:

【参考方案1】:

你正在创造你想要创造的东西。不过,这可能是也可能不是您想要创建的。

很可能,您的程序集没有特定名称,而是随机的唯一名称 - 在这种情况下,类型是完全不同的,并且就 .NET 而言只是偶然相似。来自两个不同编译的类型完全不相关,并且不兼容。当您通过在动态程序集之外定义的接口访问它们时,这可能会或可能不会出现问题,具体取决于您使用这些类型的准确程度。

如果添加程序集名称,情况会变得更复杂一些。您不能两次加载相同的程序集(旧的不会被新的替换),因此您需要更改版本。但是,不能在同一个应用程序域中加载同一个程序集的两个版本(除非用AssemblyResolve 等做“有趣” - 但这很难做到正确)。第二个程序集将无法加载。

最后,您尝试实例化的Type 是您 实例化的那个(除非使用绑定重定向,这是额外的乐趣:P)。如果您的某些代码保留了先前编译中的 Type,这就是它将创建的内容。

【讨论】:

感谢您的回答。所以我不应该遇到麻烦,因为在这种特定情况下,我不保存在 old 程序集中定义的类型的实例。非常感谢!是的,他们也没有名字,因为我在给他们名字的时候已经遇到了麻烦:) @BendEg 是的,应该可以正常工作。请注意,旧的程序集并没有被清理,所以如果您经常在同一个进程中进行编译,您可能希望将它们加载到不同的 AppDomain 中(您可以在不再有用时卸载域)。【参考方案2】:

如果您的问题是我是否在 AppDomain 中加载程序集

Assembly a1=Assembly.Load(Array of Assembly);

然后用 roslyn 类名称更改代码并创建项目的新程序集并再次加载它

Assembly a2 =Assembly.Load(Array of Assembly);

现在 a2 是否加载到 CurrentDomain 中? 我的答案是否定的。a1 现在在 CurrentDomain 中。

你可以测试一下。

因此,要使用新程序集,您必须使用以下解决方案。

您需要在另一个 AppDomain 中加载此程序集,并且每次您可以卸载此 AppDomain 并再次创建它并再次加载程序集

首先创建一个类,CurrentDomain 会将其实例加载到另一个 AppDomain,该类对象必须加载您的程序集,并且它依赖于第二个 AppDomain。

// you can create this class in another project and
// make assembly .because you need a copy of it in 
//folder that you set for ApplicationBase of second AppDomain
public class AssemblyLoader : MarshallByRefObject

    AssemblyLoader()
    
         AppDomain.CurrentAppDomain.AssemblyResolve += LoaddependencyOfAssembly;
    
public void LoaddependencyOfAssembly(object sender,)

    //load depdency of your assembly here
    // if you has replaced those dependencies  to folder that you set for ApplicationBase of second AppDomain doesn't need do anything here

public Assembly asm get;set;
public void LoadAssembly(MemoryStream ms)

     asm=  Assembly.Load(ms.ToArray());


在您要加载程序集的位置

AppDomainSetup s=new AppDomainSetup()ApplicationBase="anotherFolderFromYourAppBinFoldr;
AppDomain ad= AppDomain.CreateDomain("name",AppDomain.CurrentDomain.Evidence,s);
Type t = typeof( AssemblyLoader);
 AssemblyLoader al = ( AssemblyLoader) ad.CreateInstanceAndUnwrap(t.Assembly.FullName,t.FullName);
// load assembly here by Stream or fileName
al.LoadAssembly(ms );
// now assembly loaded on ad 
// you can do your work with this assembly by al 
// for example  create a method in AssemblyLoader to 
// get il of methods with name of them 
//  Below IL is in CurrentDomain
//when compiler goes to GetIlAsByteArray you are in second AppDomain
byte[] IL = al.GetILAsByteArray("NameOfMethod");
//And unload second AppDomain 
 AppDomain.Unload(ad);

【讨论】:

感谢您的回答。我从未使用过不同的 AppDomain。这是否允许主 AppDomain 和新创建的 AppDomain 之间轻松通信?谢谢 我在回答中说过。例如,您可以在程序集中获取 il 方法并将其返回给第一个 AppDomain。我将编辑答案 感谢您的详细回答和工作。我会试试这个然后回复你。 +2 如果我能... 我遇到了这个问题,所以我的代码可以工作。可能是打字不好。我用手机打字 更多关于AppDomains之间通信的信息msdn.microsoft.com/en-us/library/…

以上是关于在运行时多次加载 Roslyn 编译的 DLL的主要内容,如果未能解决你的问题,请参考以下文章

在 .net 核心中为 Roslyn 动态选择引用

dll加载遇到的问题

如果我想在运行时部署时查看图像,要加载啥 dll,我真的需要哪个 vc dll?

使用 Roslyn 编译时自动解析依赖关系

halcon12在C#中二次开发编译没错,运行时报: 无法加载DLL"halcon”

未能找到路径“\bin\roslyn\csc.exe”的一部分 的解决办法