制作域中立程序集的步骤是什么?

……并且这些步骤是否也可以应用于第三方程序集(可能已经强名称)?

我的问题的上下文不应该很重要,但无论如何我都会分享:我正在考虑制作一个记录器(或日志包装器),它始终知道要定位的“日志源”,无论使用它的程序集是在一个应用程序域中,或分布在多个应用程序域中。 我认为实现这一目标的一种方法是使用具有静态“LogSource”属性的域中立程序集。 如果在域中性程序集中设置了静态属性,我认为所有appdomains都会看到它。

程序集未以任何特定方式标记为域中立。 您不必为它们提供某些特定属性,以使它们与域无关。 CLR可以将任何程序集加载到共享域或触发程序集加载的域中,具体取决于加载程序集的CLR实例的配置。

CLR实例如何决定加载程序集由策略决定。 有几种方法可以明确设置此策略:

  • 在可执行文件的入口点(通常是Main)上设置LoaderOptimizationAttribute 。 CLR加载程序将在启动可执行文件时应用指定的策略。
  • 从托管代码创建新的应用程序域时设置AppDomainSetup.LoaderOptimization属性。
  • CorBindToRuntimeEx – 从非托管代码启动CLR时,此函数允许您指定启动标志 ,其中一些控制加载器优化。

作为域中立加载的程序集将加载到共享域中。 应用程序域名是CLRv4中的“EE Shared Assembly Repository”。 这不是一个真正的应用程序域,因为它没有数据,也无法运行任何代码。 加载到其中的程序集将在所有其他正在运行的应用程序域中共享其代码。 程序集中的字节代码只能进行JIT编译一次。 但是,程序集中的所有可变数据都将在运行域之间重复。 应用程序域之间不共享静态字段。 每个应用程序域静态字段将被复制,并且当引用相同的静态字段时,不同的应用程序域将在内存中的不同位置读取和写入。

另外:还有另一种静态字段–RVA静态字段,在当前进程中的所有应用程序域之间共享。 无法在C#中声明这样的字段,但可以在C ++ / CLI中完成。

在使用域中立程序集时需要权衡利弊。 访问静态字段的速度较慢。 由于它们仅被JIT-ted一次,但可以访问每个app域静态字段的多个实例,因此对静态字段的任何访问都会通过额外的间接访问。 当程序集直接加载到运行域时,静态字段的地址可以直接嵌入到JIT-ted代码中。 但是,当编译到共享程序集中的代码尝试访问静态字段时,它必须首先加载当前域的上下文,然后在其中查找此域的静态字段地址。

是否将程序集加载到共享域或运行域中的决定取决于您的用例,更具体地说,您要创建的应用程序域数以及要加载到哪种核心。

  • 如果加载多个运行本质相同代码的域,则需要尽可能多地共享程序集,除非它严重影响访问静态字段的性能。 一个示例是一个应用程序,它决定在单独的应用程序域中运行部分自己的代码,以便隔离。
  • 如果使用不同的代码加载多个域,则只需共享可能由所有不同程序集共用的程序集。 这些通常是.NET Framework自己的程序集和从GAC加载的所有程序集。 运行ASP.NET应用程序时,IIS默认以这种方式工作。
  • 如果您只使用一个应用程序域,则不应共享任何内容。 常规的GUI应用程序就是这样的。

注意:mscorlib始终加载到共享域中。

来源和进一步阅读:

  • 应用程序域和程序集
  • 域中性组件
  • Essential .NET,第1卷,Addison Wesley ; 第8章“AppDomains和代码管理”

域中立程序集仅在appdomains中共享代码。 但是,数据仍然是每个应用程序域。 因此,每个域都有一个静态LogSource属性的副本。

实际上,有一种棘手的,未记录的方式跨域共享数据,但它可能导致运行时错误和整个应用程序崩溃。 作者不建议在实际项目中使用它,因此您可以使用MarshalByRef对象来共享日志使用者。 但你也可以用这些技巧分享它。

http://geekswithblogs.net/akraus1/archive/2012/07/25/150301.aspx