appdomain回调:正在加载程序集

本文关键字:加载 程序集 回调 appdomain | 更新日期: 2023-09-27 18:00:46

我是C#的初学者,正在学习一本关于AppDomain的C#文本书。

这是我在一本教科书《坚果壳4e中的C#4.0(O’Reilly)》中发现的

让我们重新审视最基本的多域场景:

static void Main()
{
    AppDomain newDomain = AppDomain.CreateDomain ("New Domain");
    newDomain.ExecuteAssembly ("test.exe");
    AppDomain.Unload (newDomain);
}

在单独的域上调用ExecuteAssembly很方便,但提供的机会很少以与域交互。它还要求目标程序集是可执行文件,并且它将调用程序提交到单个入口点。唯一的合并方式灵活性是采用一种方法,例如将一系列参数传递给可执行文件
强大的方法是使用AppDomain的DoCallBack方法。这在另一个应用程序域上执行,该应用程序域是给定类型上的一个方法。类型的程序集会自动加载到域中(如果当前域可以引用CLR,则CLR将知道它所在的位置)。在下面的例子中,当前执行类中的一个方法在一个新域中运行:

class Program
{
    static void Main()
    {
        AppDomain newDomain = AppDomain.CreateDomain ("New Domain");
        newDomain.DoCallBack (new CrossAppDomainDelegate (SayHello));
        AppDomain.Unload (newDomain);
    }
    static void SayHello()
    {
        Console.WriteLine ("Hi from " + AppDomain.CurrentDomain.FriendlyName);
    }
}

在这里,SayHello()方法存在于同一个Program类中。根据声明,

"类型的程序集自动加载到域(CLR如果当前域可以引用它,它将知道它的位置)。"

这意味着,如果SayHello()方法存在于其他第三方程序集中,那么该程序集是否也已加载?我不理解这个说法。你能帮我一下吗?非常感谢。

appdomain回调:正在加载程序集

但几乎没有机会与领域交互

这完全是AppDomain的意义所在。其隔离程序集和数据的能力是它们存在的原因。每个AppDomain都有自己的垃圾收集堆和及时编译的代码,独立于另一个AppDomain中的代码和数据。它是一种替代方案,可以在单独的进程中运行代码,这是一种性能高得多的替代方案,因为在Windows中跨越进程边界既困难又昂贵。

这在服务器场景中得到了充分利用,SQL server和ASP.NET就是最好的例子。它们接受来自客户端的服务请求,并在单个进程中执行。隔离为服务流程提供了非常强大的生存保障。如果代码因任何原因爆炸,那么服务器可以发回"对不起,没有工作"的响应。并通过终止服务请求线程并卸载AppDomain来从未处理的异常中恢复,从而丢弃不再可靠的程序状态。服务器一直嗡嗡作响,好像什么都没发生。

在默认CLR主机上,AppDomains几乎没有实际用途,只有一个:卸载程序集的功能。它允许实现插件风格的框架,根据需要加载和卸载代码。卸载程序集在其他方面是不可能的,这会产生太多的方式,及时生成的机器代码可能会导致崩溃。在AppDomain内部生成它允许丢弃该代码,从而使卸载程序集成为可能。

当然,代价是在两个AppDomain之间交换数据很麻烦,数据必须从一个GC堆复制到另一个。NET很好地支持它,这要归功于Remoting。但是,数据本身必须能够跨除法进行复制,要么是[Serializable],以便可以按值封送,要么是从MarshalByRefObject派生,以便可以代理。

您可以使用AppDomain.Load()在AppDomain中加载程序集,并使用assembly.CreateInstance()在AppDomain中创建对象,从而进一步提升ExecuteAssembly()的基元示例。关于如何支持.NET.

中的插件,你可以在谷歌上找到很多关于这一点的文章

这意味着,如果SayHello()方法存在于其他第三方程序集,那么该程序集也被加载?

不,这并不意味着。如果我们把前一句话从文本中拆开,它将更容易理解:

这在另一个应用程序域上执行,该应用程序域是给定类型上的一个方法。

在您的示例中,方法为SayHello,类型为Program

类型的程序集自动加载到域中

定义类型的程序集将加载到新的应用程序域。这是从包含Program类的项目生成的程序集。

(如果当前域可以引用,CLR将知道它的位置它)。

CLR知道此程序集的位置,因为它已加载到主应用程序域中。对于所有加载的类型,查找包含它们的程序集的位置是很简单的。你已经在书的前几章中看到了类似的代码:

Assembly a = typeof(Program).Assembly;

Assembly a = anObject.GetType().Assembly;

一旦有了Assembly对象,就可以访问Location属性并获取加载程序集的完整路径。

因此,该语句的意思是,包含回调方法类型的程序集将自动加载到新的应用程序域中。因此,如果您想在新的AppDomain中执行任何程序集的代码,此方法非常方便。缺点是事后你没什么可做的。除非您使用某种AppDomain间通信,例如Hans提到的.NET RemotingWCF等,否则您无法与新AppDomain中的对象通信。