65.9K
CodeProject 正在变化。 阅读更多。
Home

增强的资源文件代码生成器 - 类型安全的格式化字符串

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (11投票s)

2008年7月3日

Ms-PL

5分钟阅读

viewsIcon

40205

downloadIcon

486

一个增强的 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 非常简单。只需按照以下步骤操作:

  1. 为任何格式化的 stringstring 资源编辑器的注释列中添加替换参数信息。
  2. 选择要更新的资源文件,并将自定义工具属性(位于属性窗口中)更改为 ResXFileCodeGeneratorEx。如果您需要 public 访问您的资源,请使用 PublicResXFileCodeGeneratorEx
  3. 相应地更新您的代码。

添加替换参数信息

替换参数用于构建格式化 string 的方法参数。它们在 string 资源编辑器的注释列中定义,并且是所有格式化 string 所必需的。如果 string 不包含格式化信息,则会忽略注释列的内容。

替换参数信息语法

替换参数信息的语法非常简单但灵活。它由以下规则组成:

  1. string 资源编辑器注释列用于定义格式类型和参数名称。
  2. 通用格式为:<formatType> <paramName>[, <formatType> <paramName>]
  3. 支持 XML 参数注释,即“///”注释。
  4. 支持 C# 风格的注释,即“//”注释。这些注释不会添加到代码隐藏文件中。它们通常用于帮助翻译人员进行翻译。
  5. 支持以下格式类型:stringintlongboolcharbytefloatdoubledecimalshortsbyteushortuintulong。注意: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

string address /// 不能接受邮政信箱8

string city, string state,8

string zip /// zip 必须包含 4 位扩展码。例如 43249-1234

注意:注释以回车符 (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!
© . All rights reserved.