1

我是 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() 方法存在于其他第三方程序集中,那么该程序集是否也会被加载?我不明白这个说法。你能帮我吗?谢谢你。

4

2 回答 2

2

但提供与域交互的机会很少

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

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

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

代价当然是两个 AppDomain 之间交换数据很麻烦,数据必须从一个 GC 堆复制到另一个。.NET 很好地支持它,这要归功于 Remoting。但是数据本身必须具有跨界复制的能力,要么是[Serializable],所以它可以按值封送,或者通过从MarshalByRefObject派生,所以它可以被代理。

您可以通过使用 AppDomain.Load() 在 AppDomain 中加载程序集并使用 Assembly.CreateInstance() 在 AppDomain 中创建对象来进一步提升 ExecuteAssembly() 的原始示例。几乎所有关于如何在 .NET 中支持插件的 google 点击都很好地涵盖了这一点。

于 2013-02-22T14:54:13.493 回答
0

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

不,不是那个意思。如果我们把上一句从正文中拆分出来,会更容易理解:

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

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

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

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

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

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

Assembly a = typeof(Program).Assembly;

或者

Assembly a = anObject.GetType().Assembly;

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

所以这条语句的意思是,包含回调方法类型的程序集会被自动加载到新的应用程序域中。因此,如果您想在新的AppDomain. 缺点是之后您无能为力。AppDomain除非您使用某种跨 AppDomain 通信,例如.NET RemotingHans 提到的,否则您无法与新的对象进行通信WCF

于 2013-02-22T17:50:12.877 回答