C# - 从另一个 AppDomain 中的方法返回值

Posted

技术标签:

【中文标题】C# - 从另一个 AppDomain 中的方法返回值【英文标题】:C# - Returning Value From a Method in Another AppDomain 【发布时间】:2012-09-26 22:17:31 【问题描述】:

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

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

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

我只想跑:

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

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

【问题讨论】:

您是否尝试过使用反射..?例如类型 t = typeof(YourNamespace.YourClass);字符串 assemblyQualifiedName = t.AssemblyQualifiedName;类型类型 = Type.GetType(assemblyQualifiedName, false, true); // 类型不会为空 【参考方案1】:

您将不得不对 .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"
 */

【讨论】:

完美运行。非常感谢。【参考方案2】:

一般来说,应用程序域之间共享的对象必须派生自 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(); 

【讨论】:

我试图为我的动态创建的实例设置公共属性,该实例已经实现了自定义接口。但是您的回答对我有所帮助,因为现在我只是在接口中调用一个方法并让 dll 本身设置公共属性:) 再次感谢!【参考方案3】:

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

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

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

【讨论】:

以上是关于C# - 从另一个 AppDomain 中的方法返回值的主要内容,如果未能解决你的问题,请参考以下文章

是否可以从另一个单独的 .NET AppDomain 更改 .NET AppDomain 中的字符串属性的值

C# 在 appdomain 调用方法中加载 dll,而不会再次加载 dll

在 C# 中的自定义 appdomain 中加载 dll

受限 AppDomain 中的 C# 类继承自位于主 AppDomain 中的其他类

在运行时从另一个 AppDomain 调试动态加载的 DLL

C#、MAF、单独 AppDomain 中的未处理异常管理