Resource Managers
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# | Copy Code |
---|---|
using System.Resources; using System.Reflection; |
Add a private field to the Form1
class to hold the ResourceManager
:
C# | Copy Code |
---|---|
private ResourceManager resourceManager; |
Instantiate the ResourceManager
at the beginning of the Form1
constructor:
C# | 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# | Copy Code |
---|---|
MessageBox.Show("Insufficient funds for the transfer"); |
to this:
C# | 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.resourcesIn 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.