![]() |
Platforms, Frameworks & Libraries »
.NET Framework »
General
Intermediate
License: The Microsoft Public License (Ms-PL)
Enhanced Resource File Code Generator - Type-safe Formatted StringsBy Tristen FieldingAn enhanced ResXFileCodeGenerator that handles formatted strings in a type-safe and natural way |
C# (C#1.0, C#2.0, C#3.0).NET2.0, .NET3.0, .NET3.5VS2005, VS2008, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
With the release of .NET 2.0, Microsoft provides a type-safe (code-behind) wrapper class that wraps resource files. This is a huge improvement over the old error-prone way of accessing resources. We can now access resources like images, icons, files and strings just by using the resource’s identifier as a property of this wrapper class.
For example, suppose we have an image file called MyCompanyLogo.png and a resource file called Images.resx. The resource file includes the image as follows:
name = “MyCompanyLogo” file = “.\MyCompanyLogo.png”
The code-behind file creates a class called Images and a property in that class like so:
internal Image MyCompanyLogo { get; }
Now in our source code, we can access the image file MyCompanyLogo.png simply by accessing the type-safe property:
Image pic = Images.MyCompanyLogo;
As it turns out, there is still one major problem area; runtime errors are possible when using formatted strings. A formatted string is a string that contains special replacement parameters. For example, suppose we have a string like “Welcome John” but we want to use it to display a welcome message for any user that logs on to our application. We can create a formatted string like “Welcome {0}”. The {0} is an indexed replacement parameter that allows us to use the string in the following way:
Console.WriteLine(string.Format(“Welcome {0}”, name));
At this point, we want to make the string localizable. We place it in a resource file (let’s call the file LocalizedStrings.resx and the name of the resource WelcomeMessage). Microsoft’s custom tool called ResXFileCodeGenerator creates a property called WelcomeMessage.
However, we now have a problem. Because the formatted string is defined as a property, we can easily do the following:
Console.WriteLine(LocalizedStrings.WelcomeMessage);
And the output looks like this:
Welcome {0}
Clearly that isn't what we want and thus we have a runtime bug.
The correct usage is:
Console.WriteLine(string.Format(LocalizedStrings.WelcomeMessage, name));
Another problem with this approach occurs if we decide to add more parameterized content to the string. Suppose we change the welcome message to “Welcome {0} {1}”. What is the meaning of this new replacement string? It is unclear; does it mean first name, last name, or does it mean salutation full name? In the end, it is difficult for others to discover our intent.
Also, another runtime bug occurs because we now have two replaceable parameters instead of one. We have to remember to search our code and fix every place we are using this string. This is time consuming and error-prone.
The solution is to provide a smarter layer over the existing structure provided by Visual Studio. Our new layer produces a code-behind file similar to that created by Visual Studio. Non-string resources (images, icons, etc.) and strings that do not contain replacement parameters are not altered. Strings with replacement parameters are transformed into methods that have type-safe parameters representing each of the replacement parameters.
To access a non-formatted string, no changes are required to your existing code. Simply reference the string property:
Console.WriteLine(LocalizedStrings.MyNonFormattedString);
To access a string containing format information, call the string’s method and pass in the replacement parameters:
Console.WriteLine(LocalizedStrings.WelcomeMessage(firstName, lastName));
In the above case, the WelcomeMessage string resource has the following value:
Welcome {0} {1}
In cases where access to the original strings is required, we provide an inner class called Raw. This allows developers to access any string as follows:
string rawMessage = LocalizedStrings.Raw.WelcomeMessage;
Using ResXFileCodeGeneratorEx is very straightforward. Simply follow these steps:
string resource editor for any formatted strings. ResXFileCodeGeneratorEx. If you need public access to your resources use PublicResXFileCodeGeneratorEx. Replacement parameters are used to build the method parameters for a formatted string. They are defined in the comment column of the string resource editor and are required for all formatted strings. The content of the comment column is ignored if a string does not contain formatting information.
The syntax of the replacement parameter information is very simple yet flexible. It consists of the following rules:
string resource editor comment column is used to define the format types and parameter names. <formatType> <paramName>[, <formatType> <paramName>] ///” comments. //” comments. These comments aren't added to the code-behind file. They are normally used to help the translators during translation. string, int, long, bool, char, byte, float, double, decimal, short, sbyte, ushort, uint, and ulong. Note: Object is not a valid format type since everything derives from object. Instead, convert the object to a supported format type such as string. To exclude a string from processing, simple place $exclude$ in the comment column. The string will be represented as a property even if it contains formatting information.
Here is a typical string resource editor view:
| Name | Value | Comment |
InvalidIdentifier |
Invalid class name '{0}'. |
string className |
Hi |
Hi my name is {0} and I am {1} years old. |
string name, int age |
UnformatedMessage |
C# uses { and } to define beginning and ending blocks |
$exclude$ |
Address |
{0} {1}, {2} {3} |
// Just a normal message8 |
Note: Comments are terminated by carriage returns (8). This allows for inline comments for each replacement parameter.
Here is part of the code-behind file generated from the example resources:
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) { … }
The Enhanced Resource File Code Generator source and executable can be downloaded from the links at the top of this article.
Enjoy!
| You must Sign In to use this message board. | |||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 3 Jul 2008 Editor: Deeksha Shenoy |
Copyright 2008 by Tristen Fielding Everything else Copyright © CodeProject, 1999-2010 Web20 | Advertise on the Code Project |