Clase System.Resources.ResourceReader

En este artículo se proporcionan comentarios adicionales a la documentación de referencia de esta API.

Importante

Llamar a métodos de esta clase con datos que no son de confianza supone un riesgo de seguridad. Llame a los métodos de esta clase solo con datos de confianza. Para obtener más información, vea Validar todas las entradas.

La ResourceReader clase proporciona una implementación estándar de la IResourceReader interfaz. Una ResourceReader instancia representa un archivo .resources independiente o un archivo .resources incrustado en un ensamblado. Se usa para enumerar los recursos de un archivo .resources y recuperar sus pares nombre-valor. Difiere de la ResourceManager clase , que se usa para recuperar recursos con nombre especificados de un archivo .resources incrustado en un ensamblado. La ResourceManager clase se usa para recuperar recursos cuyos nombres se conocen de antemano, mientras que la ResourceReader clase es útil para recuperar recursos cuyo número o nombres precisos no se conocen en tiempo de compilación. Por ejemplo, una aplicación puede usar un archivo de recursos para almacenar información de configuración organizada en secciones y elementos de una sección, donde el número de secciones o elementos de una sección no se conoce de antemano. A continuación, los recursos se pueden denominar genéricamente (como Section1, Section1Item1Section1Item2, etc.) y recuperarse mediante un ResourceReader objeto .

Importante

Este tipo implementa la interfaz IDisposable. Cuando haya terminado de utilizar el tipo, debe desecharlo directa o indirectamente. Para eliminar el tipo directamente, llame a su método Dispose en un bloque try/catch. Para deshacerse de él indirectamente, use una construcción de lenguaje como using (en C#) o Using (en Visual Basic). Para obtener más información, vea la sección "Using an Object that Implements IDisposable" (Usar un objeto que implementa IDisposable) en la documentación de la IDisposable interfaz.

Creación de una instancia de un objeto ResourceReader

Un archivo .resources es un archivo binario que se ha compilado a partir de un archivo de texto o un archivo .resx XML mediante Resgen.exe (Generador de archivos de recursos). Un ResourceReader objeto puede representar un archivo .resources independiente o un archivo .resources incrustado en un ensamblado.

Para crear instancias de un ResourceReader objeto que lee desde un archivo .resources independiente, use el ResourceReader constructor de clase con un flujo de entrada o una cadena que contenga el nombre del archivo .resources. En el ejemplo siguiente se muestran ambos enfoques. La primera crea una instancia de un ResourceReader objeto que representa un archivo .resources denominado Resources1.resources mediante su nombre de archivo. El segundo crea una instancia de un ResourceReader objeto que representa un archivo .resources denominado Resources2.resources mediante una secuencia creada a partir del archivo.

// Instantiate a standalone .resources file from its filename.
var rr1 = new System.Resources.ResourceReader("Resources1.resources");

// Instantiate a standalone .resources file from a stream.
var fs = new System.IO.FileStream(@".\Resources2.resources",
                                  System.IO.FileMode.Open);
var rr2 = new System.Resources.ResourceReader(fs);
' Instantiate a standalone .resources file from its filename.
Dim rr1 As New System.Resources.ResourceReader("Resources1.resources")

' Instantiate a standalone .resources file from a stream.
Dim fs As New System.IO.FileStream(".\Resources2.resources",
                                   System.IO.FileMode.Open)
Dim rr2 As New System.Resources.ResourceReader(fs)

Para crear un ResourceReader objeto que represente un archivo .resources incrustado, cree una instancia de un Assembly objeto del ensamblado en el que está incrustado el archivo .resources. Su Assembly.GetManifestResourceStream método devuelve un Stream objeto que se puede pasar al ResourceReader(Stream) constructor. En el ejemplo siguiente se crea una instancia de un ResourceReader objeto que representa un archivo .resources incrustado.

System.Reflection.Assembly assem =
             System.Reflection.Assembly.LoadFrom(@".\MyLibrary.dll");
System.IO.Stream fs =
             assem.GetManifestResourceStream("MyCompany.LibraryResources.resources");
var rr = new System.Resources.ResourceReader(fs);
Dim assem As System.Reflection.Assembly = 
             System.Reflection.Assembly.LoadFrom(".\MyLibrary.dll") 
Dim fs As System.IO.Stream = 
             assem.GetManifestResourceStream("MyCompany.LibraryResources.resources")
Dim rr As New System.Resources.ResourceReader(fs)

Enumerar los recursos de un objeto ResourceReader

Para enumerar los recursos de un archivo .resources, llame al GetEnumerator método , que devuelve un System.Collections.IDictionaryEnumerator objeto . Llame al IDictionaryEnumerator.MoveNext método para pasar de un recurso al siguiente. El método devuelve false cuando se han enumerado todos los recursos del archivo .resources.

Nota:

Aunque la ResourceReader clase implementa la IEnumerable interfaz y el IEnumerable.GetEnumerator método , el ResourceReader.GetEnumerator método no proporciona la IEnumerable.GetEnumerator implementación. En su lugar, el ResourceReader.GetEnumerator método devuelve un IDictionaryEnumerator objeto de interfaz que proporciona acceso al par nombre/valor de cada recurso.

Puede recuperar los recursos individuales de la colección de dos maneras:

Recuperación de recursos mediante las propiedades IDictionaryEnumerator

El primer método para enumerar los recursos de un archivo .resources implica recuperar directamente el par nombre/valor de cada recurso. Después de llamar al IDictionaryEnumerator.MoveNext método para desplazarse a cada recurso de la colección, puede recuperar el nombre del recurso de la IDictionaryEnumerator.Key propiedad y los datos del recurso de la IDictionaryEnumerator.Value propiedad .

En el ejemplo siguiente se muestra cómo recuperar el nombre y el valor de cada recurso de un archivo .resources mediante las IDictionaryEnumerator.Key propiedades y IDictionaryEnumerator.Value . Para ejecutar el ejemplo, cree el siguiente archivo de texto denominado ApplicationResources.txt para definir recursos de cadena.

Title="Contact Information"
Label1="First Name:"
Label2="Middle Name:"
Label3="Last Name:"
Label4="SSN:"
Label5="Street Address:"
Label6="City:"
Label7="State:"
Label8="Zip Code:"
Label9="Home Phone:"
Label10="Business Phone:"
Label11="Mobile Phone:"
Label12="Other Phone:"
Label13="Fax:"
Label14="Email Address:"
Label15="Alternate Email Address:"

A continuación, puede convertir el archivo de recursos de texto en un archivo binario denominado ApplicationResources.resources mediante el siguiente comando:

resgen ApplicationResources.txt

A continuación, en el ejemplo siguiente se usa la ResourceReader clase para enumerar cada recurso en el archivo .resources binario independiente y mostrar su nombre de clave y el valor correspondiente.

using System;
using System.Collections;
using System.Resources;

public class Example1
{
   public static void Run()
   {
      Console.WriteLine("Resources in ApplicationResources.resources:");
      ResourceReader res = new ResourceReader(@".\ApplicationResources.resources");
      IDictionaryEnumerator dict = res.GetEnumerator();
      while (dict.MoveNext())
         Console.WriteLine("   {0}: '{1}' (Type {2})", 
                           dict.Key, dict.Value, dict.Value.GetType().Name);
      res.Close();
   }
}
// The example displays the following output:
//       Resources in ApplicationResources.resources:
//          Label3: '"Last Name:"' (Type String)
//          Label2: '"Middle Name:"' (Type String)
//          Label1: '"First Name:"' (Type String)
//          Label7: '"State:"' (Type String)
//          Label6: '"City:"' (Type String)
//          Label5: '"Street Address:"' (Type String)
//          Label4: '"SSN:"' (Type String)
//          Label9: '"Home Phone:"' (Type String)
//          Label8: '"Zip Code:"' (Type String)
//          Title: '"Contact Information"' (Type String)
//          Label12: '"Other Phone:"' (Type String)
//          Label13: '"Fax:"' (Type String)
//          Label10: '"Business Phone:"' (Type String)
//          Label11: '"Mobile Phone:"' (Type String)
//          Label14: '"Email Address:"' (Type String)
//          Label15: '"Alternate Email Address:"' (Type String)
Imports System.Collections
Imports System.Resources

Module Example2
    Public Sub Main()
        Console.WriteLine("Resources in ApplicationResources.resources:")
        Dim res As New ResourceReader(".\ApplicationResources.resources")
        Dim dict As IDictionaryEnumerator = res.GetEnumerator()
        Do While dict.MoveNext()
            Console.WriteLine("   {0}: '{1}' (Type {2})", dict.Key, dict.Value, dict.Value.GetType().Name)
        Loop
        res.Close()
    End Sub
End Module
' The example displays output like the following:
'       Resources in ApplicationResources.resources:
'          Label3: '"Last Name:"' (Type String)
'          Label2: '"Middle Name:"' (Type String)
'          Label1: '"First Name:"' (Type String)
'          Label7: '"State:"' (Type String)
'          Label6: '"City:"' (Type String)
'          Label5: '"Street Address:"' (Type String)
'          Label4: '"SSN:"' (Type String)
'          Label9: '"Home Phone:"' (Type String)
'          Label8: '"Zip Code:"' (Type String)
'          Title: '"Contact Information"' (Type String)
'          Label12: '"Other Phone:"' (Type String)
'          Label13: '"Fax:"' (Type String)
'          Label10: '"Business Phone:"' (Type String)
'          Label11: '"Mobile Phone:"' (Type String)
'          Label14: '"Email Address:"' (Type String)
'          Label15: '"Alternate Email Address:"' (Type String)

El intento de recuperar datos de recursos de la IDictionaryEnumerator.Value propiedad puede producir las siguientes excepciones:

Normalmente, estas excepciones se producen si el archivo .resources se ha modificado manualmente, si el ensamblado en el que se define un tipo no se ha incluido con una aplicación o se ha eliminado accidentalmente, o si el ensamblado es una versión anterior que predefini un tipo. Si se produce una de estas excepciones, puede recuperar recursos mediante la enumeración de cada recurso y la llamada al GetResourceData método , como se muestra en la sección siguiente. Este enfoque proporciona información sobre el tipo de datos que la IDictionaryEnumerator.Value propiedad intentó devolver.

Recuperación de recursos por nombre con GetResourceData

El segundo enfoque para enumerar recursos en un archivo .resources también implica navegar por los recursos del archivo llamando al IDictionaryEnumerator.MoveNext método . Para cada recurso, se recupera el nombre del recurso de la IDictionaryEnumerator.Key propiedad , que se pasa al GetResourceData(String, String, Byte[]) método para recuperar los datos del recurso. Esto se devuelve como una matriz de bytes en el resourceData argumento .

Este enfoque es más incómodo que recuperar el nombre y el valor del recurso de las IDictionaryEnumerator.Key propiedades y IDictionaryEnumerator.Value , porque devuelve los bytes reales que forman el valor del recurso. Sin embargo, si el intento de recuperar el recurso produce una excepción, el GetResourceData método puede ayudar a identificar el origen de la excepción proporcionando información sobre el tipo de datos del recurso. Para obtener más información sobre la cadena que indica el tipo de datos del recurso, vea GetResourceData.

En el ejemplo siguiente se muestra cómo usar este enfoque para recuperar recursos y controlar las excepciones que se producen. Crea mediante programación un archivo .resources binario que contiene cuatro cadenas, un valor booleano, un entero y un mapa de bits. Para ejecutar el ejemplo, haga lo siguiente:

  1. Compile y ejecute el código fuente siguiente, que crea un archivo .resources denominado ContactResources.resources.

    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Resources;
    using System.Runtime.Versioning;
    
    public class Example5
    {
        [SupportedOSPlatform("windows")]
        public static void Run()
        {
            // Bitmap as stream.
            MemoryStream bitmapStream = new MemoryStream();
            Bitmap bmp = new Bitmap(@".\ContactsIcon.jpg");
            bmp.Save(bitmapStream, ImageFormat.Jpeg);
    
            // Define resources to be written.
            using (ResourceWriter rw = new ResourceWriter(@".\ContactResources.resources"))
            {
                rw.AddResource("Title", "Contact List");
                rw.AddResource("NColumns", 5);
                rw.AddResource("Icon", bitmapStream);
                rw.AddResource("Header1", "Name");
                rw.AddResource("Header2", "City");
                rw.AddResource("Header3", "State");
                rw.AddResource("ClientVersion", true);
                rw.Generate();
            }
        }
    }
    

    El archivo de código fuente se denomina CreateResources.cs. Puede compilarlo en C# mediante el siguiente comando:

    csc CreateResources.cs /r:library.dll
    
  2. Compile y ejecute el código siguiente para enumerar los recursos en el archivo ContactResources.resources.

    using System;
    using System.Collections;
    using System.Drawing;
    using System.IO;
    using System.Resources;
    using System.Runtime.Versioning;
    
    public class Example6
    {
        [SupportedOSPlatform("windows")]
        public static void Run()
        {
            ResourceReader rdr = new ResourceReader(@".\ContactResources.resources");
            IDictionaryEnumerator dict = rdr.GetEnumerator();
            while (dict.MoveNext())
            {
                Console.WriteLine("Resource Name: {0}", dict.Key);
                try
                {
                    Console.WriteLine("   Value: {0}", dict.Value);
                }
                catch (FileNotFoundException)
                {
                    Console.WriteLine("   Exception: A file cannot be found.");
                    DisplayResourceInfo(rdr, (string)dict.Key, false);
                }
                catch (FormatException)
                {
                    Console.WriteLine("   Exception: Corrupted data.");
                    DisplayResourceInfo(rdr, (string)dict.Key, true);
                }
                catch (TypeLoadException)
                {
                    Console.WriteLine("   Exception: Cannot load the data type.");
                    DisplayResourceInfo(rdr, (string)dict.Key, false);
                }
            }
        }
    
        [SupportedOSPlatform("windows")]
        private static void DisplayResourceInfo(ResourceReader rr,
                                        string key, bool loaded)
        {
            string dataType = null;
            byte[] data = null;
            rr.GetResourceData(key, out dataType, out data);
    
            // Display the data type.
            Console.WriteLine("   Data Type: {0}", dataType);
            // Display the bytes that form the available data.      
            Console.Write("   Data: ");
            int lines = 0;
            foreach (var dataItem in data)
            {
                lines++;
                Console.Write("{0:X2} ", dataItem);
                if (lines % 25 == 0)
                    Console.Write("\n         ");
            }
            Console.WriteLine();
            // Try to recreate current state of data.
            // Do: Bitmap, DateTimeTZI
            switch (dataType)
            {
                // Handle internally serialized string data (ResourceTypeCode members).
                case "ResourceTypeCode.String":
                    BinaryReader reader = new BinaryReader(new MemoryStream(data));
                    string binData = reader.ReadString();
                    Console.WriteLine("   Recreated Value: {0}", binData);
                    break;
                case "ResourceTypeCode.Int32":
                    Console.WriteLine("   Recreated Value: {0}",
                                      BitConverter.ToInt32(data, 0));
                    break;
                case "ResourceTypeCode.Boolean":
                    Console.WriteLine("   Recreated Value: {0}",
                                      BitConverter.ToBoolean(data, 0));
                    break;
                // .jpeg image stored as a stream.
                case "ResourceTypeCode.Stream":
                    const int OFFSET = 4;
                    int size = BitConverter.ToInt32(data, 0);
                    Bitmap value1 = new Bitmap(new MemoryStream(data, OFFSET, size));
                    Console.WriteLine("   Recreated Value: {0}", value1);
                    break;
                default:
                    break;
            }
            Console.WriteLine();
        }
    }
    

    Después de modificar el código fuente (por ejemplo, iniciando deliberadamente un FormatException al final del try bloque), puede ejecutar el ejemplo para ver cómo las llamadas para GetResourceData permitirle recuperar o volver a crear alguna información de recursos.