Resource Managers

Release 1.0 - ...

Resource managers retrieve resources. The .NET Framework versions 1.1 and 2.0 include two resource-manager classes, System.Resources.ResourceManager and its descendant, System.ComponentModel.ComponentResourceManager. The former is used in all .NET applications, whereas the latter is typically used only in Visual Studio 2005 Windows Forms applications.

When an attempt to load a resource is made (using ResourceManager.GetString or ResourceManager.GetObject), the Resource Manager looks through its internal cache of resources to see if the request can be supplied from the cache. If not, a ResourceSet is loaded from a resource embedded in an assembly. A ResourceSet is a collection of resource entries and is equivalent to an in-memory copy of a single .resx file (you can think of a ResourceSet as a DataTable for resource entries). The ResourceSet is added to the ResourceManager’s internal cache. Finally, the ResourceSet is searched for the resource entry that matches the requested key.

To retrieve the string, we need to create a ResourceManager object and call its GetString method.

Example

Create a new C# Windows Forms application. Add a couple of using directives to Form1.cs:

C# CopyCode image Copy Code
using System.Resources; using System.Reflection;

Add a private field to the Form1 class to hold the ResourceManager:

C# CopyCode image Copy Code
private ResourceManager resourceManager;

Instantiate the ResourceManager at the beginning of the Form1 constructor:

C# CopyCode image Copy Code
public Form1() {
  resourceManager = new ResourceManager(
    "WindowsApplication1.Form1Resources",
    Assembly.GetExecutingAssembly()
  );
  InitializeComponent();
}

The first parameter to the ResourceManager constructor is the fully qualified name of the resource that we want to retrieve. Recall from the assembly’s manifest that the resource was called “WindowsApplication1.Form1Resources.resources.” The ResourceManager class adds the “.resources” suffix so that it should not be included in the name passed to the constructor. The second parameter to the ResourceManager constructor is the assembly in which this resource can be found. In this example and most others like it, we are saying that the resource can be found in the assembly that is currently executing: i.e. WindowsApplication1.exe.

All that remains is for us to retrieve the string using the ResourceManager. Change the original hard-coded line from this:

C# CopyCode image Copy Code
MessageBox.Show("Insufficient funds for the transfer");

to this:

C# CopyCode image Copy Code
MessageBox.Show(resourceManager.GetString("InsufficientFunds"));

The ResourceManager.GetString method gets a string from the resource: “InsufficientFunds” is the key of the resource, and GetString returns the value that corresponds to this key.

At this point, we have a localizable application; it is capable of being localized, but it has not yet been localized. In this example, we add French to the list of supported languages. This is where the culture strings that we discussed earlier come in. The culture string for neutral French is “fr.” Create a new Resource File using the same name as before, but use a suffix of “.fr.resx” instead of just “.resx” so that the complete filename is Form1Resources.fr.resx. Into this resource file, add a new string, using the same name as before, “InsufficientFunds” into the Value field this time, though, type the French equivalent of “Insufficient funds for the transfer” (i.e., “Fonds insuffisants pour le transfert”).

Compile the application and inspect the output folder. You will find a new folder called “fr” beneath the output folder. If the output folder is \WindowsApplication1\bin\Debug, you will find WindowsApplication1\bin\Debug\fr. In this folder you will find a new assembly with the same name as the application, but with the extension “.resources.dll” (i.e., WindowsApplication1.resources.dll).

The Form1Resources.fr.resx file has been compiled and embedded in this new assembly. This new assembly is a resources assembly, and it contains resources only. This assembly is referred to as a satellite assembly. If you inspect the manifest of this satellite assembly using ILDASM (<frameworksdk>\bin\ildasm.exe), you will find the following line:

  .mresource public WindowsApplication1.Form1Resources.fr.resources
In this way, you can support any number of languages simply by having subfolders with the same name as the culture. When you deploy your application, you can include as many or as few of the subfolders as you want. In addition, if you update one or more resources, you need to deploy only the updated resource assemblies, not the whole application.