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

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

【问题讨论】:

    标签: c# .net-assembly appdomain roslyn


    【解决方案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/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多