ResourceManager

The ResourceManager class provides convenient access to culture-correct resources at run time. A ResourceManager manages multiple resources from a common source that has a particular root name. Multiple class constructors provide support for different scenarios, including retrieving resources from assemblies and resources files. A separate, static method supports retrieving resources from stand-alone resource files, such as images. The default implementation loads all the resource names and then loads the values on demand, storing them for later use. This uses less memory than the ResourceSet class (which is discussed later in this section), assuming not all resources are loaded, but initially retrieving a specific resource might take longer. In addition, the default ResourceManager implementation supports object serialization. Finally, ResourceManager objects provide fallback resource lookup to region-independent and neutral cultures when specific localized resources are not provided.

You already looked at a simple mechanism — using a ResourceReader — to enumerate resources. You will now use the powerful ResourceManager to do roughly the same thing.

Listing 4a. Named Resources with ResourceManager (ResWrite.cs)

...
ResourceManager rm = ResourceManager. 
    CreateFileBasedResourceManager("sample", ".", null);
Console.WriteLine(rm.GetString("test1"));
Console.WriteLine(rm.GetString("test2"));
Console.WriteLine(rm.GetString("test3"));
Console.WriteLine(rm.GetString("test4"));
Console.WriteLine(rm.GetObject("test5").ToString());
...

Listing 4b. Named Resources with ResourceManager (ResWrite.vb)

...
Dim rm As ResourceManager = ResourceManager. 
   CreateFileBasedResourceManager ("sample", ".", Nothing)
Console.WriteLine(rm.GetString("test1"))
Console.WriteLine(rm.GetString("test2"))
Console.WriteLine(rm.GetString("test3"))
Console.WriteLine(rm.GetString("test4"))
Console.WriteLine(rm.GetObject("test5").ToString())
...

The first thing to notice is the static CreateFileBasedResourceManager method, which takes three arguments: the file, the location, and whether a nondefault ResourceSet is to be used. (The code assumes that the location is the application's base directory, which is named AppBase.) The next thing to notice is how easy it is to retrieve string resources using the GetString method of the ResourceManager class.

You can also use the GetObject method to retrieve an image resource. The previous example simply writes the value of the name of the resource, but the following two lines of code (which are taken from the Graphic.cs sample file) show how to use this method to retrieve and display a graphic image:

rm = new ResourceManager("Images", this.GetType().Assembly);
pictureBox1.Image = (System.Drawing.Image)rm.GetObject("flag");

Here is the Visual Basic equivalent from the Graphic.vb sample file:

rm = New ResourceManager("Images", Me.GetType().Assembly)
pictureBox1.Image = CType(rm.GetObject("flag"), System.Drawing.Image)

The previous two statements load the object named flag from the Images resources file, cast it to an Image type, and assign the result to the Image property of the picture box. What actually gets loaded, of course, depends on which culture is being used. For neutral culture resources, the resources come from what was specified by the compiler option, which is shown here:

.../res:Images.resources,Images.resources...

In this particular case, the compiler option embedded the Un.jpg file. For other cultures, the bitmap was embedded into the corresponding satellite assembly during the build process.

The ResourceManager works with any serializable data, in other words, those classes that are marked with the Serializable attribute and that support the ISerializable interface. The built-in types include the Image type (and the Bitmap, Icon, Cursor, and Metafile derived types) and the string types. Note that ResourceManager string parameters are case-sensitive, meaning that resource file names and resource keys are all case-sensitive.

Files can be located in subdirectories or .resources files, or they can be packaged in assemblies. To locate a resource in an assembly, ResourceManager takes the name of the executing assembly, appends ".resources" and its own Major.Minor version number, adds the current locale, adds the signature key hash for the current executing assembly, and tells the assembly cache to locate this assembly. For a discussion of a useful tool for tracing assembly-cache bind requests, refer to the documentation on the Assembly Binding Log Viewer (FusLogVW) in Appendix B: Resource Tools.

**Note   **If you choose to implement stand-alone, loose resources in individual files and you are running a Web-based application, you might encounter file locking by Microsoft Internet Information Services (IIS), which will prevent you from updating the resource files while the application is running. If, instead, you place the resources in satellite assemblies in the application's \bin subdirectory, the IIS shadow-copy mechanism will ensure that the new resources are automatically loaded when creating a new application domain to handle subsequent Web requests.