附属程序集加载算法
使用附属程序集来存储为语言和区域性自定义的本地化资源。
附属程序集使用不同于常规托管程序集的加载算法。
何时加载附属程序集?
加载本地化资源时加载附属程序集。
加载本地化资源的基本 API 是 System.Resources.ResourceManager 类。 最后,ResourceManager 类将为每个 CultureInfo.Name 调用 GetSatelliteAssembly 方法。
较高级别的 API 可能会提取低级别 API。
算法
.NET Core 资源回退进程包含以下步骤:
确定
active
AssemblyLoadContext 实例。 在所有情况下,active
实例都是执行程序集的 AssemblyLoadContext。active
实例按以下优先级顺序加载请求区域性的附属程序集:检查其缓存。
如果
active
是 AssemblyLoadContext.Default 实例,则运行默认附属(资源)程序集探测逻辑。调用 AssemblyLoadContext.Load 函数。
如果从文件加载了对应于附属程序集的托管程序集,请检查托管程序集的目录,以获取与所请求 CultureInfo.Name 匹配的子目录(例如
es-MX
)。注意
在 Linux 和 macOS 上,子目录区分大小写,并且必须是以下两种情况之一:
- 完全匹配大小写。
- 为小写。
引发 AppDomain.AssemblyResolve 事件。
如果加载附属程序集:
- 引发 AppDomain.AssemblyLoad 事件。
- 将搜索程序集以查找请求的资源。 如果运行时在程序集中找到该资源,则使用它。 如果找不到该资源,将继续搜索。
注意
要在附属程序集中查找资源,运行时将搜索 ResourceManager 为当前 CultureInfo.Name 请求的资源文件。 在资源文件中,它搜索请求的资源名称。 如果找不到上述任何一个,则资源将被视为未找到。
ResourceManager 接下来通过许多潜在级别搜索父区域性程序集,每次均重复步骤 2 和 3。
每个区域性只有一个父级,由 CultureInfo.Parent 属性定义。
当区域性的 Parent 属性为 CultureInfo.InvariantCulture 时,父区域性搜索将停止。
对于 InvariantCulture,我们不会返回到步骤 2 和 3,而是继续执行步骤 5。
如果仍未找到资源,则 ResourceManager 将使用默认(回退)区域性的资源。
通常,默认区域性的资源包含在主应用程序集中。 不过,可以为 NeutralResourcesLanguageAttribute.Location 属性指定 UltimateResourceFallbackLocation.Satellite。 此值指示资源的最终回退位置是附属程序集,而不是主程序集。
注意
默认区域性为最终回退。 因此,建议在默认资源文件中始终包含一组详尽的资源。 这有助于防止引发异常。 通过拥有详尽资源集,可为所有资源提供回退,并确保始终向用户呈现至少一种资源,即使该资源不是特定于区域性的。
最后,
- 如果运行时找不到默认(回退)区域性的资源文件,将引发 MissingManifestResourceException 或 MissingSatelliteAssemblyException 异常。
- 如果找到资源文件但是请求的资源不存在,则请求返回
null
。