appdomain回调:程序集加载

时间:2013-02-22 10:10:06

标签: c# appdomain

我是C#的初学者,我正在研究有关AppDomain的C#教科书。

这是我在教科书“C#4.0 in a Nutshell 4e(O'Reilly)”中找到的内容

让我们重新审视最基本的多域方案:

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

在单独的域上调用ExecuteAssembly很方便,但几乎没有机会 与域进行交互。它还要求目标组件是一个 可执行文件,它将调用者提交到单个入口点。合并的唯一方法 灵活性是采用一种方法,例如传递一串参数 可执行文件 强大的方法是使用AppDomain的DoCallBack方法。 这在另一个应用程序域上执行,即给定类型的方法。类型的程序集会自动加载到域中(如果当前域可以引用它,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()方法存在于某些其他第三方程序集中,那么该程序集也会加载? 我不明白这个说法。你能帮帮我吗?谢谢。

2 个答案:

答案 0 :(得分:2)

  

但几乎没有机会与域名进行互动

这完全是AppDomain的重点。它隔离组件和数据的能力是它们存在的原因。每个AppDomain都有自己的垃圾收集堆和即时编译代码,独立于另一个AppDomain中的代码和数据。它是在单独的进程中运行代码的替代方案,因为在Windows中跨越进程边界既困难又昂贵,因此是一种更高效的替代方案。

在服务器方案中利用了这一点,SQL Server和ASP.NET是主要的例子。它们接受来自客户端的服务请求并在单个进程中执行它。隔离为服务过程提供了非常强大的生存保障。如果代码炸弹出于任何原因,那么服务器可以发回“抱歉,没有工作”的响应。并通过终止服务请求线程并卸载AppDomain从未处理的异常中恢复,丢弃不再可靠的程序状态。服务器保持嗡嗡声,好像什么也没发生。

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

当然,价格是在两个AppDomain之间交换数据很麻烦,数据必须从一个GC堆复制到另一个GC堆。由于Remoting,.NET很好地支持它。但是数据本身必须具有跨越鸿沟的能力,可以是[Serializable],因此它可以通过值封送,或者从MarshalByRefObject派生,因此可以代理。

通过使用AppDomain.Load()在AppDomain和Assembly.CreateInstance()中加载程序集以在AppDomain中创建对象,可以进一步提升ExecuteAssembly()的原始示例。几乎所有关于如何在.NET中支持插件的谷歌搜索都会详细介绍。

答案 1 :(得分:0)

  

这意味着,如果其他第三方存在SayHello()方法   程序集,然后还加载了程序集?

不,这并不意味着。如果我们从文本中拆分上一句话,那将更容易理解:

  

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

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

  

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

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

  

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

CLR知道此程序集的位置,因为它已在主应用程序域中加载。对于所有加载的类型,找到包含它们的程序集的位置是微不足道的。您已在本书前面的章节中看到过:

Assembly a = typeof(Program).Assembly;

Assembly a = anObject.GetType().Assembly;

获得Assembly对象后,您可以访问Location属性并获取已加载程序集的完整路径。

所以这个语句的意思是包含回调方法类型的程序集将自动加载到新的应用程序域。因此,如果要从新AppDomain中的任何程序集执行代码,此方法很方便。缺点是你之后没有其他的事情可做。您无法与新AppDomain中的对象进行通信,除非您使用某种类型的AppDomain间通信,例如Hans提到的.NET RemotingWCF等。