4

我有一个场景,我从 C# 代码中的操作将 DLL 添加到 GAC。然后我需要对新添加的 DLL 执行 Assembly.Load。但是,由于进程启动时 DLL 不在 GAC 中,因此它返回 null。

所以,我看到代码可以在不同的 AppDomain 中运行,这将导致 DLL 可以从单独的 AppDomain 中的 GAC 获得。

如何将另一个 AppDomain 的值返回到我的主线程?

我只是想运行:

var type = Assembly.Load(assembly).GetType(className);

并让它从另一个 AppDomain 返回到我的主线程。

4

3 回答 3

10

您将不得不使用 .NET Remoting 进行一些操作。您在另一个 AppDomain 上加载的对象需要从 MarshalByRefObject 类 ( http://msdn.microsoft.com/en-us/library/system.marshalbyrefobject.aspx ) 派生。

只是为了节省时间,这是该链接中的代码:

using System;
using System.Reflection;

public class Worker : MarshalByRefObject
{
    public void PrintDomain() 
    { 
        Console.WriteLine("Object is executing in AppDomain \"{0}\"",
            AppDomain.CurrentDomain.FriendlyName); 
    }
}

class Example
{
    public static void Main()
    {
        // Create an ordinary instance in the current AppDomain
        Worker localWorker = new Worker();
        localWorker.PrintDomain();

        // Create a new application domain, create an instance 
        // of Worker in the application domain, and execute code 
        // there.
        AppDomain ad = AppDomain.CreateDomain("New domain");
        Worker remoteWorker = (Worker) ad.CreateInstanceAndUnwrap(
            Assembly.GetExecutingAssembly().FullName,
            "Worker");
        remoteWorker.PrintDomain();
    }
}

/* This code produces output similar to the following:

Object is executing in AppDomain "source.exe"
Object is executing in AppDomain "New domain"
 */
于 2012-09-26T22:56:47.160 回答
5

一般来说,应用程序域之间共享的对象必须派生自MarshalByRefObject。如果类型是在动态加载的 DLL 中定义的,则返回实际类型会出现问题。由于该类型在主线程的 AppDomain 中不可用。您可以将其转换为已在主应用程序线程中加载的 DLL 中可用的基类。

我过去所做的是为我想在应用程序域之间共享的类创建一个接口。显然,该接口将位于主应用程序和动态加载的 dll 共享的一些基本 dll 中。

在您的基础 dll 中,您可以声明您的接口:

public interface IMyBaseInterface
{
     void DoStuff();
}

然后在动态加载的dll中,该类实现接口并派生自MarshalByRefObject:

public class MyDynamicClass : MarshalByRefObject, IMyBaseInterface
{
    public void DoStuff()
    {
        Console.WriteLine("Hello other app domain!");
    }
}

加载对象实例的代码如下所示:

AppDomainSetup ads = new AppDomainSetup();
AppDomain appDomain = AppDomain.CreateDomain(_appDomainName, null, ads);
IMyBaseInterface myObj = (IMyBaseInterface) appDomain.CreateInstanceAndUnwrap(assemblyName, typeName);
myObj.DoStuff(); 
于 2012-09-26T23:03:39.137 回答
2

当您通过 AppDomain 边界“泄漏”对象(在您的情况下隐式或显式)时,必须将实现程序集加载到两个域中。

正如您已经注意到的,在第一次从 AppDomain 中的程序集向一个类请求时,程序集不在 GAC 中,不会加载到 AppDomain(事实上它不是 GAC 被缓存到 AppDomain 生命周期结束,因为它不是预计装配会神奇地出现在 GAC 中)。

我认为您必须在新的 AppDomain 中保留来自新 GAC 程序集的类。

于 2012-09-26T23:06:09.667 回答