增强的资源文件代码生成器 - 类型安全的格式化字符串
一个增强的 ResXFileCodeGenerator,以类型安全和自然的方式处理格式化字符串。
更新
[2010/10/21] 安装程序已更新,支持 Visual Studio 2008 和 Visual Studio 2010!
引言
随着 .NET 2.0 的发布,Microsoft 提供了一个类型安全的(代码隐藏)包装器类来包装资源文件。这比以前容易出错的访问资源的方式有了巨大的改进。我们现在可以通过使用资源标识符作为该包装器的属性来访问图像、图标、文件和字符串等资源。
例如,假设我们有一个名为 MyCompanyLogo.png 的图像文件和一个名为 Images.resx 的资源文件。资源文件中包含如下图像:
name = “MyCompanyLogo” file = “.\MyCompanyLogo.png”
代码隐藏文件创建一个名为 Images
的类,并在该类中创建如下属性:
internal Image MyCompanyLogo { get; }
现在,在我们的源代码中,我们可以通过访问类型安全的属性来简单地访问 MyCompanyLogo.png 图像文件:
Image pic = Images.MyCompanyLogo;
问题
事实证明,仍然存在一个主要的问题区域;当使用格式化字符串时,可能会出现运行时错误。格式化字符串是指包含特殊替换参数的 string
。例如,假设我们有一个类似“Welcome John
”的 string
,但我们想用它来向登录我们应用程序的任何用户显示欢迎消息。我们可以创建一个格式化字符串,例如“Welcome {0}
”。{0}
是一个索引替换参数,它允许我们按以下方式使用该 string
:
Console.WriteLine(string.Format(“Welcome {0}”, name));
此时,我们希望使该 string
可本地化。我们将其放在一个资源文件中(我们称该文件为 LocalizedStrings.resx,资源名称为 WelcomeMessage
)。Microsoft 的自定义工具 ResXFileCodeGenerator
会创建一个名为 WelcomeMessage
的属性。
但是,现在我们遇到了一个问题。因为格式化 string
被定义为一个属性,我们可以轻松地这样做:
Console.WriteLine(LocalizedStrings.WelcomeMessage);
输出如下:
Welcome {0}
显然,这不是我们想要的,因此存在一个运行时错误。
正确用法是:
Console.WriteLine(string.Format(LocalizedStrings.WelcomeMessage, name));
此方法还会出现另一个问题,即如果我们决定向 string
添加更多参数化内容。假设我们将欢迎消息更改为“Welcome {0} {1}
”。这个新的替换 string
的含义是什么?不清楚;是表示名字、姓氏,还是表示称谓全名?最终,其他人很难理解我们的意图。
此外,由于我们现在有两个而不是一个可替换参数,因此还会发生另一个运行时错误。我们必须记住搜索我们的代码并修复使用此 string
的每个地方。这既耗时又容易出错。
解决方案
解决方案是提供一个更智能的层来覆盖 Visual Studio 提供的现有结构。我们的新层生成一个与 Visual Studio 创建的代码隐藏文件类似的类。非字符串资源(图像、图标等)和不包含替换参数的 string
不会受到更改。包含替换参数的 String
被转换为具有类型安全参数的方法,这些参数代表每个替换参数。
要访问非格式化 string
,无需更改现有代码。只需引用 string
属性:
Console.WriteLine(LocalizedStrings.MyNonFormattedString);
要访问包含格式信息的 string
,请调用该 string
的方法并传入替换参数:
Console.WriteLine(LocalizedStrings.WelcomeMessage(firstName, lastName));
在上述情况下,WelcomeMessage string
资源的值如下:
Welcome {0} {1}
在需要访问原始 string
的情况下,我们提供了一个名为 Raw
的内部类。这允许开发人员按如下方式访问任何 string
:
string rawMessage = LocalizedStrings.Raw.WelcomeMessage;
用法
使用 ResXFileCodeGeneratorEx
非常简单。只需按照以下步骤操作:
- 为任何格式化的
string
在string
资源编辑器的注释列中添加替换参数信息。 - 选择要更新的资源文件,并将自定义工具属性(位于属性窗口中)更改为
ResXFileCodeGeneratorEx
。如果您需要public
访问您的资源,请使用PublicResXFileCodeGeneratorEx
。 - 相应地更新您的代码。
添加替换参数信息
替换参数用于构建格式化 string
的方法参数。它们在 string
资源编辑器的注释列中定义,并且是所有格式化 string
所必需的。如果 string
不包含格式化信息,则会忽略注释列的内容。
替换参数信息语法
替换参数信息的语法非常简单但灵活。它由以下规则组成:
string
资源编辑器注释列用于定义格式类型和参数名称。- 通用格式为:
<formatType> <paramName>[, <formatType> <paramName>]
- 支持 XML 参数注释,即“
///
”注释。 - 支持 C# 风格的注释,即“
//
”注释。这些注释不会添加到代码隐藏文件中。它们通常用于帮助翻译人员进行翻译。 - 支持以下格式类型:
string
、int
、long
、bool
、char
、byte
、float
、double
、decimal
、short
、sbyte
、ushort
、uint
和ulong
。注意:Object 不是有效的格式类型,因为所有类型都派生自 object。而是,将 object 转换为受支持的格式类型,例如string
。
要将 string
排除在处理之外,只需在注释列中键入 $exclude$
。即使该 string
包含格式化信息,它仍将被表示为一个属性。
示例
这是一个典型的字符串资源编辑器视图:
名称 | 值 | 注释 |
InvalidIdentifier |
无效类名 '{0} '。 |
string className |
Hi |
你好,我叫 {0} ,我今年 {1} 岁。 |
string name, int age |
UnformatedMessage |
C# 使用 { 和 } 来定义开始和结束块。 |
$exclude$ |
地址 |
{0} {1} , {2} {3} |
// 一个普通的留言8 |
注意:注释以回车符 (8
) 结束。这允许为每个替换参数进行行内注释。
这是从示例资源生成的部分代码隐藏文件:
public string InvalidIdentifier(string className) {…}
public string Hi(string name, int age) {…}
public string UnformatedMessage { get {…} }
/// <param name = “address”>Can't accept PO boxes</param>
/// <param name = “zip”>
/// The zip must include the 4 digit extension. I.e. 43249-1234
/// </param>
public string Address(string address, string city, string state, string zip) { … }
增强资源文件代码生成器的源代码和可执行文件可从本文顶部链接下载。
尽情享用!
历史
- 2008 年 7 月 3 日:首次发布
- 2010 年 10 月 21 日:安装程序已更新,支持 Visual Studio 2008 和 Visual Studio 2010!