本文提供了此 API 参考文档的补充说明。
重要
使用不受信任的数据调用此类中的方法存在安全风险。 仅在确保数据受信任的情况下,再从该类调用方法。 有关详细信息,请参阅验证所有输入。
ResourceManager 类从嵌入在程序集中的二进制 .resources 文件或独立的 .resources 文件中检索资源。 如果应用已本地化,并且已将本地化资源部署到 附属程序集,则会查找特定文化的资源,在本地化资源不存在时提供资源回退机制,并支持资源序列化。
桌面应用
对于桌面应用,ResourceManager 类从二进制资源(.resources)文件检索资源。 通常,语言编译器或 程序集链接器(AL.exe) 将这些资源文件嵌入程序集中。 通过调用 CreateFileBasedResourceManager 方法,还可以使用 ResourceManager 对象直接从未嵌入到程序集的 .resources 文件中检索资源。
谨慎
在 ASP.NET 应用中使用独立 .resources 文件会中断 XCOPY 部署,因为资源将保持锁定状态,直到 ReleaseAllResources 方法显式释放它们。 如果要将资源与 ASP.NET 应用程序一起部署,则应将 .resources 文件编译为附属程序集。
在基于资源的应用中,一个 .resources 文件包含默认文化的资源,如果找不到特定文化的资源,则会使用该默认资源。 例如,如果某个应用的默认文化是英语(en),那么在找不到特定文化的本地化资源时,例如英语(美国)(en-US)或法语(法国)(fr-FR),将使用英语语言资源。 通常,会将默认文化的资源嵌入到主应用程序集中,而将其他本地化文化的资源嵌入到附属程序集中。 附属程序集仅包含资源。 它们的根文件名与主程序集相同,扩展名为 .resources.dll。 对于未在全局程序集缓存中注册程序集的应用,会将附属程序集存储在应用子目录中,该子目录的名称与程序集的文化对应。
创建资源
开发基于资源的应用时,可将资源信息存储在文本文件(具有 .txt 或 .restext 扩展名的文件)或 XML 文件(扩展名为 .resx 的文件) 中。 然后使用 资源文件生成器(Resgen.exe) 编译文本或 XML 文件,以创建二进制 .resources 文件。 然后,可以使用编译器选项(如 C# 和 Visual Basic 编译器的 /resources
)将生成的 .resources 文件嵌入到可执行文件或库中,也可以使用 程序集链接器(AI.exe)将其嵌入附属程序集中。 如果在 Visual Studio 项目中包括 .resx 文件,Visual Studio 会在生成过程中自动处理默认和本地化资源的编译和嵌入。
理想情况下,应为应用支持的每种语言创建资源,或者至少为每个语言的有意义的子集创建资源。 二进制 .resources 文件名遵循命名约定 basename。cultureName.resources,其中 basename 是应用的名称或类的名称,具体取决于所需的详细信息级别。 CultureInfo.Name 属性用于确定 cultureName。 应用默认文化的资源应命名为 basename.resources。
例如,假设程序集在一个基本名称为 MyResources 的资源文件中有多个资源。 这些资源文件应该命名为 MyResources.ja-JP.resources 以适应日本(日本语)文化,MyResources.de.resources 适应德语文化,MyResources.zh-CHS.resources 适应简体中文文化,以及 MyResources.fr-BE.resources 适应法语(比利时)文化。 默认资源文件应命名为 MyResources.resources。 文化特定资源文件通常会打包成每个文化的附属程序集。 默认资源文件应嵌入应用的主程序集中。
请注意,程序集链接器 允许将资源标记为私有,但应始终将它们标记为公共,以便其他程序集可以访问它们。 (由于附属程序集不包含任何代码,因此标记为私有的资源无法通过任何机制让应用程序使用。)
有关创建、打包和部署资源的详细信息,请参阅文章 创建资源文件、创建附属程序集,以及 打包和部署资源。
实例化 ResourceManager 对象
通过调用类构造函数重载之一,可实例化 ResourceManager 对象,以便从嵌入的 .resources 文件中检索资源。 这会将 ResourceManager 对象与特定 .resources 文件以及附属程序集中的任何关联本地化 .resources 文件紧密耦合。
最常调用的两个构造函数是:
ResourceManager(String, Assembly) 根据提供的两条信息查找资源:.resources 文件的基名称,以及默认 .resources 文件所在的程序集。 基名称包括 .resources 文件的命名空间和根名称,但不包含其文化信息或扩展名。 请注意,从命令行编译的 .resources 文件通常不包括命名空间名称,而 Visual Studio 环境中创建的 .resources 文件通常包括命名空间名称。 例如,如果资源文件名为 MyCompany.StringResources.resources,并且从名为
Example.Main
的静态方法调用 ResourceManager 构造函数,则以下代码实例化可从 .resources 文件中检索资源的 ResourceManager 对象:ResourceManager rm = new ResourceManager("MyCompany.StringResources", typeof(Example).Assembly);
Dim rm As New ResourceManager("MyCompany.StringResources", GetType(Example2).Assembly)
ResourceManager(Type) 会根据类型对象中的信息在附属程序集中查找资源。 该类型的完全限定名称与 .resources 文件的基本名称相对应,不包含文件扩展名。 在使用 Visual Studio 资源设计器创建的桌面应用中,Visual Studio 将创建一个包装类,该包装器类的完全限定名称与 .resources 文件的根名称相同。 例如,如果资源文件名为 MyCompany.StringResources.resources,并且存在名为
MyCompany.StringResources
的包装类,则以下代码实例化一个 ResourceManager 对象,该对象可以从 .resources 文件检索资源:ResourceManager rm = new ResourceManager(typeof(MyCompany.StringResources));
Dim rm As New ResourceManager(GetType(MyCompany.StringResources))
如果找不到适当的资源,构造函数调用将创建有效的 ResourceManager 对象。 但是,尝试检索资源会引发 MissingManifestResourceException 异常。 有关处理异常的信息,请参阅本文后面的处理 MissingManifestResourceException 和 MissingSatelliteAssemblyException 异常部分。
以下示例演示如何实例化 ResourceManager 对象。 它包含名为 ShowTime.exe的可执行文件的源代码。 它还包括一个名为 Strings.txt 的文本文件,其中包含一个字符串资源 TimeHeader
。
TimeHeader=The current time is
可以使用批处理文件生成资源文件并将其嵌入可执行文件。 下面是使用 C# 编译器生成可执行文件的批处理文件:
resgen strings.txt
csc ShowTime.cs /resource:strings.resources
对于 Visual Basic 编译器,可以使用以下批处理文件:
resgen strings.txt
vbc ShowTime.vb /resource:strings.resources
using System;
using System.Resources;
public class ShowTimeEx
{
public static void Main()
{
ResourceManager rm = new ResourceManager("Strings",
typeof(Example).Assembly);
string timeString = rm.GetString("TimeHeader");
Console.WriteLine($"{timeString} {DateTime.Now:T}");
}
}
// The example displays output like the following:
// The current time is 2:03:14 PM
Imports System.Resources
Module Example6
Public Sub Main()
Dim rm As New ResourceManager("Strings", GetType(Example6).Assembly)
Dim timeString As String = rm.GetString("TimeHeader")
Console.WriteLine("{0} {1:T}", timeString, Date.Now)
End Sub
End Module
' The example displays output similar to the following:
' The current time is 2:03:14 PM
ResourceManager 和文化特定资源
本地化应用需要部署资源,如 打包和部署资源一文中所述。 如果正确配置了程序集,资源管理器会根据当前线程的 Thread.CurrentUICulture 属性确定要检索的资源。 (该属性还返回当前线程的 UI 区域性。例如,如果使用主程序集中的默认英语语言资源以及两个附属程序集中的法语和俄语资源编译应用,并且 Thread.CurrentUICulture 属性设置为 fr-FR,则资源管理器将检索法语资源。
可以显式或隐式设置 CurrentUICulture 属性。 你设置的方式决定了 ResourceManager 对象如何根据文化检索资源。
如果将 Thread.CurrentUICulture 属性显式设置为特定文件,则不管用户采用哪种浏览器或操作系统语言,资源管理器始终会检索该文件的资源。 请考虑一个使用默认英语语言资源以及三个包含英语(美国)、法语(法国)和俄语(俄罗斯)资源的附属程序集编译的应用程序。 如果 CurrentUICulture 属性设置为 fr-FR,则即使用户的作系统语言不是法语,ResourceManager 对象始终检索法语(法国)资源。 在显式设置属性之前,确保这是所需的行为。
在 ASP.NET 应用中,必须显式设置 Thread.CurrentUICulture 属性,因为服务器上的设置不太可能与传入的客户端请求匹配。 ASP.NET 应用可以将 Thread.CurrentUICulture 属性显式设置为用户的浏览器接受语言。
显式设置 Thread.CurrentUICulture 属性定义该线程的当前用户界面文化。 它不会影响应用程序中其他线程的当前 UI 文化。
可以通过将表示该区域性的 CultureInfo 对象分配给静态 CultureInfo.DefaultThreadCurrentUICulture 属性来设置应用域中所有线程的 UI 区域性。
如果未显式设置当前 UI 区域性,并且未为当前应用域定义默认区域性,则 Windows
GetUserDefaultUILanguage
函数会隐式设置 CultureInfo.CurrentUICulture 属性。 此函数由多语言用户界面(MUI)提供,使用户能够设置默认语言。 如果用户未设置 UI 语言,则默认为系统安装的语言,即作系统资源的语言。
以下简单的“Hello world”示例中明确设置当前 UI 文化设置。 它包含三种文化的资源:英语(美国)或 en-US、法语(法国)或 fr-FR,以及俄罗斯(俄罗斯)或 ru-RU。 en-US 资源包含在名为 Greetings.txt的文本文件中:
HelloString=Hello world!
fr-FR 资源包含在名为 Greetings.fr-FR.txt的文本文件中:
HelloString=Salut tout le monde!
ru-RU 资源包含在名为 Greetings.ru-RU.txt的文本文件中:
HelloString=Всем привет!
下面是示例的源代码(Visual Basic 版本Example.vb或 C# 版本的Example.cs):
using System;
using System.Globalization;
using System.Resources;
using System.Threading;
public class Example
{
public static void Main()
{
// Create array of supported cultures
string[] cultures = { "en-CA", "en-US", "fr-FR", "ru-RU" };
Random rnd = new Random();
int cultureNdx = rnd.Next(0, cultures.Length);
CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture;
ResourceManager rm = new ResourceManager("Greetings", typeof(Example).Assembly);
try
{
CultureInfo newCulture = new CultureInfo(cultures[cultureNdx]);
Thread.CurrentThread.CurrentCulture = newCulture;
Thread.CurrentThread.CurrentUICulture = newCulture;
string greeting = String.Format("The current culture is {0}.\n{1}",
Thread.CurrentThread.CurrentUICulture.Name,
rm.GetString("HelloString"));
Console.WriteLine(greeting);
}
catch (CultureNotFoundException e)
{
Console.WriteLine($"Unable to instantiate culture {e.InvalidCultureName}");
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture;
Thread.CurrentThread.CurrentUICulture = originalCulture;
}
}
}
// The example displays output like the following:
// The current culture is ru-RU.
// Всем привет!
Imports System.Globalization
Imports System.Resources
Imports System.Threading
Module Example
Sub Main()
' Create array of supported cultures
Dim cultures() As String = {"en-CA", "en-US", "fr-FR", "ru-RU" }
Dim rnd As New Random()
Dim cultureNdx As Integer = rnd.Next(0, cultures.Length)
Dim originalCulture As CultureInfo = Thread.CurrentThread.CurrentCulture
Dim rm As New ResourceManager("Greetings", GetType(Example).Assembly)
Try
Dim newCulture As New CultureInfo(cultures(cultureNdx))
Thread.CurrentThread.CurrentCulture = newCulture
Thread.CurrentThread.CurrentUICulture = newCulture
Dim greeting As String = String.Format("The current culture is {0}.{1}{2}",
Thread.CurrentThread.CurrentUICulture.Name,
vbCrLf, rm.GetString("HelloString"))
Console.WriteLine(greeting)
Catch e As CultureNotFoundException
Console.WriteLine("Unable to instantiate culture {0}", e.InvalidCultureName)
Finally
Thread.CurrentThread.CurrentCulture = originalCulture
Thread.CurrentThread.CurrentUICulture = originalCulture
End Try
End Sub
End Module
' The example displays output like the following:
' The current culture is ru-RU.
' Всем привет!
若要编译此示例,请创建一个包含以下命令的批处理(.bat)文件,并从命令提示符运行它。 如果使用 C#,请指定 csc
而不是 vbc
,而不是 Example.cs
而不是 Example.vb
。
resgen Greetings.txt
vbc Example.vb /resource:Greetings.resources
resgen Greetings.fr-FR.txt
Md fr-FR
al /embed:Greetings.fr-FR.resources /culture:fr-FR /out:fr-FR\Example.resources.dll
resgen Greetings.ru-RU.txt
Md ru-RU
al /embed:Greetings.ru-RU.resources /culture:ru-RU /out:ru-RU\Example.resources.dll
检索资源
调用 GetObject(String) 和 GetString(String) 方法来访问特定资源。 还可以调用 GetStream(String) 方法以字节数组的形式检索非字符串资源。 默认情况下,在具有本地化资源的应用中,这些方法会返回由进行调用的线程当前 UI 文化确定的文化资源。 请参阅上一部分,ResourceManager 和与文化特定相关的资源,了解如何定义线程的当前 UI 文化。 如果资源管理器找不到当前线程 UI 文化的资源,则将使用回退流程来检索指定的资源。 如果资源管理器找不到任何本地化资源,则将使用默认文化的资源。 有关资源回退规则的详细信息,请参阅 打包和部署资源一文的“资源回退过程”部分。
注释
如果找不到在 ResourceManager 类构造函数中指定的 .resources 文件,则尝试检索资源将引发 MissingManifestResourceException 或 MissingSatelliteAssemblyException 异常。 有关处理异常的信息,请参阅本文后面的处理 MissingManifestResourceException 和 MissingSatelliteAssemblyException 异常部分。
以下示例使用 GetString 方法检索文化特定的资源。 它包括从英语(en)、法语(法国)(fr-FR)和俄罗斯(俄罗斯)(ru-RU)文化的 .txt 文件中编译的资源。 本示例将当前文化和当前 UI 文化更改为英语(美国)、法语(法国)、俄语(俄罗斯)和瑞典语(瑞典)。 然后,它调用 GetString 方法来检索本地化字符串,该字符串与当前日和月份一起显示。 请注意,在输出中显示了适当的本地化字符串,但当当前 UI 文化为瑞典(瑞典)时除外。 由于瑞典语言资源不可用,因此应用会改用默认区域性的资源,即英语。
此示例需要下表中列出的基于文本的资源文件。 每个资源都有一个字符串资源,命名为 DateStart
。
文化 | 文件名 | 资源名称 | 资源值 |
---|---|---|---|
en-US | DateStrings.txt | DateStart |
今天是 |
fr-FR | DateStrings.fr-FR.txt | DateStart |
Aujourd'hui, c'est le |
ru-RU | DateStrings.ru-RU.txt | DateStart |
Сегодня |
下面是示例的源代码(visual Basic 版本ShowDate.vb或 C# 版本的代码ShowDate.cs)。
using System;
using System.Globalization;
using System.Resources;
using System.Threading;
[assembly: NeutralResourcesLanguage("en")]
public class ShowDateEx
{
public static void Main()
{
string[] cultureNames = { "en-US", "fr-FR", "ru-RU", "sv-SE" };
ResourceManager rm = new ResourceManager("DateStrings",
typeof(Example).Assembly);
foreach (var cultureName in cultureNames)
{
CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
Console.WriteLine($"Current UI Culture: {CultureInfo.CurrentUICulture.Name}");
string dateString = rm.GetString("DateStart");
Console.WriteLine($"{dateString} {DateTime.Now:M}.\n");
}
}
}
// The example displays output similar to the following:
// Current UI Culture: en-US
// Today is February 03.
//
// Current UI Culture: fr-FR
// Aujourd'hui, c'est le 3 février
//
// Current UI Culture: ru-RU
// Сегодня февраля 03.
//
// Current UI Culture: sv-SE
// Today is den 3 februari.
Imports System.Globalization
Imports System.Resources
Imports System.Threading
<Assembly:NeutralResourcesLanguage("en")>
Module Example5
Public Sub Main()
Dim cultureNames() As String = {"en-US", "fr-FR", "ru-RU", "sv-SE"}
Dim rm As New ResourceManager("DateStrings",
GetType(Example5).Assembly)
For Each cultureName In cultureNames
Dim culture As CultureInfo = CultureInfo.CreateSpecificCulture(cultureName)
Thread.CurrentThread.CurrentCulture = culture
Thread.CurrentThread.CurrentUICulture = culture
Console.WriteLine("Current UI Culture: {0}",
CultureInfo.CurrentUICulture.Name)
Dim dateString As String = rm.GetString("DateStart")
Console.WriteLine("{0} {1:M}.", dateString, Date.Now)
Console.WriteLine()
Next
End Sub
End Module
' The example displays output similar to the following:
' Current UI Culture: en-US
' Today is February 03.
'
' Current UI Culture: fr-FR
' Aujourd'hui, c'est le 3 février
'
' Current UI Culture: ru-RU
' Сегодня февраля 03.
'
' Current UI Culture: sv-SE
' Today is den 3 februari.
若要编译此示例,请创建一个包含以下命令的批处理文件,并从命令提示符运行它。 如果使用 C#,请指定 csc
而不是 vbc
,而不是 showdate.cs
而不是 showdate.vb
。
resgen DateStrings.txt
vbc showdate.vb /resource:DateStrings.resources
md fr-FR
resgen DateStrings.fr-FR.txt
al /out:fr-FR\Showdate.resources.dll /culture:fr-FR /embed:DateStrings.fr-FR.resources
md ru-RU
resgen DateStrings.ru-RU.txt
al /out:ru-RU\Showdate.resources.dll /culture:ru-RU /embed:DateStrings.ru-RU.resources
有两种方法可用于检索非当前 UI 文化的特定文化的资源:
- 可以调用方法 GetString(String, CultureInfo)、GetObject(String, CultureInfo)或 GetStream(String, CultureInfo) 来检索特定文化的资源。 如果找不到本地化资源,资源管理器将使用资源回退过程来查找适当的资源。
- 可以调用 GetResourceSet 方法来获取一个 ResourceSet 对象,该对象表示某个特定文化的资源。 在方法调用中,可以确定资源管理器在找不到本地化资源时是否探测父文化,或者是否仅回退到默认文化的资源。 然后,可以使用 ResourceSet 方法按名称访问资源(针对该文化进行本地化),或者枚举资源集合中的资源。
处理 MissingManifestResourceException 和 MissingSatelliteAssemblyException 异常
如果尝试检索特定资源,但资源管理器找不到该资源,并且未定义默认区域性或无法找到默认区域性的资源,如果资源管理器期望在主程序集找到这些资源,它将引发 MissingManifestResourceException 异常;如果期望在附属程序集找到这些资源,则将引发 MissingSatelliteAssemblyException 异常。 请注意,异常是在调用资源检索方法(如 GetString 或 GetObject)时抛出的,而不是在实例化 ResourceManager 对象时。
在以下情况下通常会引发异常:
不存在相应的资源文件或卫星程序集。 如果资源管理器要求应用的默认资源嵌入到主应用程序集中,则不存在这些资源。 如果 NeutralResourcesLanguageAttribute 属性指示应用的默认资源驻留在附属程序集中,则找不到该程序集。 编译应用时,请确保资源嵌入主程序集或生成必要的附属程序集,并相应地命名。 其名称应采用 appName.resources.dll的格式,并且应位于一个以其包含资源的文化命名的目录中。
应用程序未定义默认或中立文化环境。 将 NeutralResourcesLanguageAttribute 属性添加到源代码文件或项目信息文件(AssemblyInfo.vb Visual Basic 应用或 C# 应用AssemblyInfo.cs) 文件。
ResourceManager(String, Assembly) 构造函数中的
baseName
参数未指定 .resources 文件的名称。 该名称应包括资源文件的完全限定命名空间,但不包括其文件扩展名。 通常,在 Visual Studio 中创建的资源文件包括命名空间名称,但在命令提示符下创建和编译的资源文件不会。 可以通过编译并运行以下实用工具来确定嵌入的 .resources 文件的名称。 这是一个控制台应用,它接受主程序集或附属程序集的名称作为命令行参数。 它显示应作为baseName
参数提供的字符串,以便资源管理器能够正确标识资源。using System; using System.IO; using System.Reflection; public class Example0 { public static void Main() { if (Environment.GetCommandLineArgs().Length == 1) { Console.WriteLine("No filename."); return; } string filename = Environment.GetCommandLineArgs()[1].Trim(); // Check whether the file exists. if (! File.Exists(filename)) { Console.WriteLine($"{filename} does not exist."); return; } // Try to load the assembly. Assembly assem = Assembly.LoadFrom(filename); Console.WriteLine($"File: {filename}"); // Enumerate the resource files. string[] resNames = assem.GetManifestResourceNames(); if (resNames.Length == 0) Console.WriteLine(" No resources found."); foreach (var resName in resNames) Console.WriteLine($" Resource: {resName.Replace(".resources", "")}"); Console.WriteLine(); } }
Imports System.IO Imports System.Reflection Imports System.Resources Module Example Public Sub Main() If Environment.GetCommandLineArgs.Length = 1 Then Console.WriteLine("No filename.") Exit Sub End If Dim filename As String = Environment.GetCommandLineArgs(1).Trim() ' Check whether the file exists. If Not File.Exists(filename) Then Console.WriteLine("{0} does not exist.", filename) Exit Sub End If ' Try to load the assembly. Dim assem As Assembly = Assembly.LoadFrom(filename) Console.WriteLine("File: {0}", filename) ' Enumerate the resource files. Dim resNames() As String = assem.GetManifestResourceNames() If resNames.Length = 0 Then Console.WriteLine(" No resources found.") End If For Each resName In resNames Console.WriteLine(" Resource: {0}", resName.Replace(".resources", "")) Next Console.WriteLine() End Sub End Module
显式更改应用程序的当前文化设置时,应牢记,资源管理器是根据 CultureInfo.CurrentUICulture 属性的值而非 CultureInfo.CurrentCulture 属性来检索资源集的。 通常,如果更改一个值,则还应更改另一个值。
资源版本控制
由于包含应用的默认资源的主程序集独立于应用的附属程序集,因此无需重新部署附属程序集即可释放主程序集的新版本。 您使用 SatelliteContractVersionAttribute 属性来使用现有的卫星程序集,并指示资源管理器在新版主程序集发布时不要重新部署这些程序集。
有关对卫星程序集的版本管理支持的详细信息,请参阅文章 检索资源。
<satelliteassemblies> 配置文件节点
注释
本部分特定于 .NET Framework 应用。
对于从网站(HREF .exe 文件)部署和运行的可执行文件,ResourceManager 对象可能会通过网站探测卫星程序集,这可能会损害应用的性能。 若要消除性能问题,可以将此探测限制为随应用部署的附属程序集。 为此,请在应用的配置文件中创建一个 <satelliteassemblies>
节点,以指定已为应用部署了一组特定的区域性,并且 ResourceManager 对象不应尝试探测该节点中未列出的任何区域性。
注释
创建 <satelliteassemblies>
节点的首选替代方法是使用 ClickOnce 部署清单功能。
在应用的配置文件中,创建类似于下面的部分:
<?xml version ="1.0"?>
<configuration>
<satelliteassemblies>
<assembly name="MainAssemblyName, Version=versionNumber, Culture=neutral, PublicKeyToken=null|yourPublicKeyToken">
<culture>cultureName1</culture>
<culture>cultureName2</culture>
<culture>cultureName3</culture>
</assembly>
</satelliteassemblies>
</configuration>
编辑此配置信息,如下所示:
为每个部署的主程序集指定一个或多个
<assembly>
节点,其中每个节点指定完全限定的程序集名称。 指定主程序集的名称代替 MainAssemblyName,并指定与主程序集对应的Version
、PublicKeyToken
和Culture
属性值。对于
Version
属性,请指定程序集的版本号。 例如,程序集的第一个版本可能是版本号 1.0.0.0。对于
PublicKeyToken
属性,如果尚未使用强名称对程序集进行签名,请指定关键字null
;如果已对程序集签名,请指定公钥令牌。对于
Culture
属性,请指定关键字neutral
以标识主要程序集,并使 ResourceManager 类只查找在<culture>
节点中列出的文化。有关完全限定程序集名称的详细信息,请参阅 程序集名称的文章。 有关强名称程序集的详细信息,请参阅 创建和使用强名称程序集的文章。
使用特定文化名称指定一个或多个
<culture>
节点,例如“fr-FR”或中性文化名称,例如“fr”。
如果 <satelliteassemblies>
节点下未列出的任何程序集都需要资源,则 ResourceManager 类会使用标准探测规则探测文化。
Windows 8.x 应用
重要
尽管 Windows 8.x 应用中支持 ResourceManager 类,但我们不建议使用它。 仅在开发可用于 Windows 8.x 应用的可移植类库项目时才使用该类。 若要从 Windows 8.x 应用检索资源,请改用 Windows.ApplicationModel.Resources.ResourceLoader 类。
对于 Windows 8.x 应用,ResourceManager 类从包资源索引 (PRI) 文件检索资源。 单个 PRI 文件(应用程序包 PRI 文件)包含默认文化及任何本地化文化的资源。 使用 MakePRI 实用工具从 XML 资源 (.resw) 格式的一个或多个资源文件创建 PRI 文件。 对于 Visual Studio 项目中包含的资源,Visual Studio 会自动处理创建和打包 PRI 文件的过程。 然后,可以使用 .NET ResourceManager 类访问应用或库的资源。
可以实例化 Windows 8.x 应用的 ResourceManager 对象,方式与为桌面应用实例化一样。
然后,您可以通过将要检索的资源名称传递给 GetString(String) 方法来访问特定文化的资源。 默认情况下,此方法会会返回进行调用的线程的当前 UI 文化确定的文化的资源。 通过将资源的名称和表示要检索资源的文件的 CultureInfo 对象传递给 GetString(String, CultureInfo) 方法,还可以检索特定文化的资源。 如果找不到当前 UI 文化或指定文化的资源,则资源管理器会使用 UI 语言回退列表来找到合适的资源。
例子
以下示例演示如何使用显式文化和隐式当前 UI 文化从主程序集和卫星程序集获取字符串资源。 有关详细信息,请参阅 创建附属程序集 主题的“未安装在全局程序集缓存中的附属程序集的目录位置”部分。
若要运行此示例,
在应用目录中,创建一个名为 rmc.txt 的文件,其中包含以下资源字符串:
day=Friday year=2006 holiday="Cinco de Mayo"
使用 资源文件生成器 从 rmc.txt 输入文件生成 rmc.resources 资源文件,如下所示:
resgen rmc.txt
创建应用目录的子目录并将其命名为“es-MX”。 这是将在接下来的三个步骤中将创建的附属程序集的文化名称。
在 es-MX 目录中创建一个名为 rmc.es-MX.txt 的文件,其中包含以下资源字符串:
day=Viernes year=2006 holiday="Cinco de Mayo"
使用 资源文件生成器 从 rmc.es-MX.txt 输入文件中生成 rmc 和es-MX.resources 资源文件,如下所示:
resgen rmc.es-MX.txt
假定此示例的文件名rmc.vb或rmc.cs。 将以下源代码复制到文件中。 然后编译它,并在可执行程序集中嵌入主程序集资源文件 rmc.resources。 如果使用 Visual Basic 编译器,则语法为:
vbc rmc.vb /resource:rmc.resources
C# 编译器的相应语法为:
csc /resource:rmc.resources rmc.cs
使用程序集链接器创建附属程序集。 如果应用的基名称为 rmc,则附属程序集名称必须为 rmc.resources.dll。 应在 es-MX 目录中创建卫星程序集。 如果 es-MX 是当前目录,请使用以下命令:
al /embed:rmc.es-MX.resources /c:es-MX /out:rmc.resources.dll
运行 rmc.exe 以获取并显示嵌入的资源字符串。
using System; using System.Globalization; using System.Resources; class Example2 { public static void Main() { string day; string year; string holiday; string celebrate = "{0} will occur on {1} in {2}.\n"; // Create a resource manager. ResourceManager rm = new ResourceManager("rmc", typeof(Example).Assembly); Console.WriteLine("Obtain resources using the current UI culture."); // Get the resource strings for the day, year, and holiday // using the current UI culture. day = rm.GetString("day"); year = rm.GetString("year"); holiday = rm.GetString("holiday"); Console.WriteLine(celebrate, holiday, day, year); // Obtain the es-MX culture. CultureInfo ci = new CultureInfo("es-MX"); Console.WriteLine("Obtain resources using the es-MX culture."); // Get the resource strings for the day, year, and holiday // using the specified culture. day = rm.GetString("day", ci); year = rm.GetString("year", ci); holiday = rm.GetString("holiday", ci); // --------------------------------------------------------------- // Alternatively, comment the preceding 3 code statements and // uncomment the following 4 code statements: // ---------------------------------------------------------------- // Set the current UI culture to "es-MX" (Spanish-Mexico). // Thread.CurrentThread.CurrentUICulture = ci; // Get the resource strings for the day, year, and holiday // using the current UI culture. Use those strings to // display a message. // day = rm.GetString("day"); // year = rm.GetString("year"); // holiday = rm.GetString("holiday"); // --------------------------------------------------------------- // Regardless of the alternative that you choose, display a message // using the retrieved resource strings. Console.WriteLine(celebrate, holiday, day, year); } } /* This example displays the following output: Obtain resources using the current UI culture. "5th of May" will occur on Friday in 2006. Obtain resources using the es-MX culture. "Cinco de Mayo" will occur on Viernes in 2006. */
Imports System.Resources Imports System.Reflection Imports System.Threading Imports System.Globalization Class Example4 Public Shared Sub Main() Dim day As String Dim year As String Dim holiday As String Dim celebrate As String = "{0} will occur on {1} in {2}." & vbCrLf ' Create a resource manager. Dim rm As New ResourceManager("rmc", GetType(Example4).Assembly) Console.WriteLine("Obtain resources using the current UI culture.") ' Get the resource strings for the day, year, and holiday ' using the current UI culture. day = rm.GetString("day") year = rm.GetString("year") holiday = rm.GetString("holiday") Console.WriteLine(celebrate, holiday, day, year) ' Obtain the es-MX culture. Dim ci As New CultureInfo("es-MX") Console.WriteLine("Obtain resources using the es-MX culture.") ' Get the resource strings for the day, year, and holiday ' using the es-MX culture. day = rm.GetString("day", ci) year = rm.GetString("year", ci) holiday = rm.GetString("holiday", ci) ' --------------------------------------------------------------- ' Alternatively, comment the preceding 3 code statements and ' uncomment the following 4 code statements: ' ---------------------------------------------------------------- ' Set the current UI culture to "es-MX" (Spanish-Mexico). ' Thread.CurrentThread.CurrentUICulture = ci ' Get the resource strings for the day, year, and holiday ' using the current UI culture. ' day = rm.GetString("day") ' year = rm.GetString("year") ' holiday = rm.GetString("holiday") ' --------------------------------------------------------------- ' Regardless of the alternative that you choose, display a message ' using the retrieved resource strings. Console.WriteLine(celebrate, holiday, day, year) End Sub End Class ' This example displays the following output: 'Obtain resources using the current UI culture. '"5th of May" will occur on Friday in 2006. ' 'Obtain resources using the es-MX culture. '"Cinco de Mayo" will occur on Viernes in 2006.