Compartilhar via


Classe System.Resources.ResourceReader

Este artigo fornece comentários complementares à documentação de referência para esta API.

Importante

Chamar métodos dessa classe com dados não confiáveis é um risco à segurança. Chame os métodos dessa classe apenas com dados confiáveis. Para obter mais informações, consulte Validar Todas as Entradas.

A ResourceReader classe fornece uma implementação padrão da IResourceReader interface. Uma instância ResourceReader representa um arquivo .resources autônomo ou um arquivo .resources incorporado em um assembly. Ele é usado para enumerar os recursos em um arquivo .resources e recuperar seus pares nome/valor. Ela difere da ResourceManager classe, que é usada para recuperar recursos nomeados especificados de um arquivo .resources inserido em um assembly. A ResourceManager classe é usada para recuperar recursos cujos nomes são conhecidos com antecedência, enquanto a ResourceReader classe é útil para recuperar recursos cujo número ou nomes precisos não são conhecidos em tempo de compilação. Por exemplo, um aplicativo pode usar um arquivo de recursos para armazenar informações de configuração organizadas em seções e itens em uma seção, em que o número de seções ou itens em uma seção não é conhecido com antecedência. Os recursos podem então ser nomeados genericamente (comoSection1, , Section1Item1Section1Item2e assim por diante) e recuperados usando um ResourceReader objeto.

Importante

Esse tipo implementa a IDisposable interface. Quando terminar de usar esse tipo ou objeto, você deverá descartá-lo de forma direta ou indireta. Para descartar o tipo diretamente, chame o método Dispose dele em um bloco try/catch. Para descartá-lo indiretamente, use um constructo de linguagem como using (em C#) ou Using (no Visual Basic). Para obter mais informações, consulte a seção "Usando um objeto que implementa idisposable" na documentação da IDisposable interface.

Criar uma instância de ResourceReader

Um arquivo .resources é um arquivo binário que foi compilado de um arquivo de texto ou de um arquivo .resx XML por Resgen.exe (Gerador de Arquivos de Recurso). Um ResourceReader objeto pode representar um arquivo .resources autônomo ou um arquivo .resources que foi embutido em um assembly.

Para criar uma instância de um objeto ResourceReader que lê de um arquivo .resources autônomo, use o construtor ResourceReader de classe com um fluxo de entrada ou uma cadeia de caracteres que contém o nome do arquivo .resources. O exemplo a seguir ilustra ambas as abordagens. O primeiro instancia um objeto ResourceReader que representa um arquivo .resources chamado Resources1.resources pelo nome de seu arquivo. O segundo cria uma instância de um objeto ResourceReader que representa um arquivo .resources chamado Resources2.resources, usando um fluxo criado a partir do arquivo.

// 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 criar um ResourceReader objeto que representa um arquivo .resources inserido, instancie um Assembly objeto do assembly no qual o arquivo .resources está inserido. Seu Assembly.GetManifestResourceStream método retorna um Stream objeto que pode ser passado para o ResourceReader(Stream) construtor. O exemplo a seguir cria uma instância de um objeto ResourceReader que representa um arquivo .resources incorporado.

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 os recursos de um objeto ResourceReader

Para enumerar os recursos em um arquivo .resources, você chama o GetEnumerator método, que retorna um System.Collections.IDictionaryEnumerator objeto. Você chama o IDictionaryEnumerator.MoveNext método para passar de um recurso para o outro. O método retorna false quando todos os recursos no arquivo .resources foram enumerados.

Observação

Embora a ResourceReader classe implemente a IEnumerable interface e o IEnumerable.GetEnumerator método, o ResourceReader.GetEnumerator método não fornece a IEnumerable.GetEnumerator implementação. Em vez disso, o ResourceReader.GetEnumerator método retorna um IDictionaryEnumerator objeto de interface que fornece acesso ao par nome/valor de cada recurso.

Você pode recuperar os recursos individuais na coleção de duas maneiras:

Recuperar recursos usando propriedades IDictionaryEnumerator

O primeiro método de enumeração dos recursos em um arquivo .resources envolve a recuperação direta do par nome/valor de cada recurso. Depois de chamar o método IDictionaryEnumerator.MoveNext para mover para cada recurso na coleção, você poderá recuperar o nome do recurso da propriedade IDictionaryEnumerator.Key e os dados do recurso da propriedade IDictionaryEnumerator.Value.

O exemplo a seguir mostra como recuperar o nome e o valor de cada recurso em um arquivo .resources usando as propriedades IDictionaryEnumerator.Key e IDictionaryEnumerator.Value. Para executar o exemplo, crie o arquivo de texto a seguir chamado ApplicationResources.txt para definir recursos de cadeia de caracteres.

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:"

Em seguida, você pode converter o arquivo de recurso de texto em um arquivo binário chamado ApplicationResources.resources usando o seguinte comando:

resgen ApplicationResources.txt

O exemplo a seguir usa a ResourceReader classe para enumerar cada recurso no arquivo .resources binário autônomo e exibir seu nome de chave e o valor correspondente.

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($"   {dict.Key}: '{dict.Value}' (Type {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)

A tentativa de recuperar dados de recurso da IDictionaryEnumerator.Value propriedade pode gerar as seguintes exceções:

  • Um erro FormatException se os dados não estiverem no formato esperado.
  • Um FileNotFoundException se o assembly que contém o tipo ao qual os dados pertencem não puder ser encontrado.
  • Um TypeLoadException se o tipo ao qual os dados pertencem não puder ser encontrado.

Normalmente, essas exceções serão geradas se o arquivo .resources tiver sido modificado manualmente, se o assembly no qual um tipo é definido não tiver sido incluído em um aplicativo ou tiver sido excluído inadvertidamente ou se o assembly for uma versão mais antiga que antecede um tipo. Se uma dessas exceções for gerada, você poderá recuperar recursos enumerando cada recurso e chamando o GetResourceData método, como mostra a seção a seguir. Essa abordagem fornece algumas informações sobre o tipo de dados que a IDictionaryEnumerator.Value propriedade tentou retornar.

Recuperar recursos por nome com GetResourceData

A segunda abordagem para enumerar recursos em um arquivo .resources também envolve navegar pelos recursos no arquivo chamando o IDictionaryEnumerator.MoveNext método. Para cada recurso, você recupera o nome do recurso da IDictionaryEnumerator.Key propriedade, que é passada para o GetResourceData(String, String, Byte[]) método para recuperar os dados do recurso. Isso é retornado como uma matriz de bytes no resourceData argumento.

Essa abordagem é mais desajeitada do que recuperar o nome e o valor do recurso das propriedades IDictionaryEnumerator.Key e IDictionaryEnumerator.Value, pois retorna os bytes reais que formam o valor do recurso. No entanto, se a tentativa de recuperar o recurso gerar uma exceção, o GetResourceData método poderá ajudar a identificar a origem da exceção fornecendo informações sobre o tipo de dados do recurso. Para obter mais informações sobre a cadeia de caracteres que indica o tipo de dados do recurso, consulte GetResourceData.

O exemplo a seguir ilustra como usar essa abordagem para recuperar recursos e lidar com quaisquer exceções geradas. Ele cria programaticamente um arquivo .resources binário que contém quatro cadeias de caracteres, um booliano, um inteiro e um bitmap. Para executar o exemplo, faça o seguinte:

  1. Compile e execute o código-fonte a seguir, que cria um arquivo .resources chamado 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();
            }
        }
    }
    

    O arquivo de código-fonte é nomeado CreateResources.cs. Você pode compilá-lo em C# usando o seguinte comando:

    csc CreateResources.cs /r:library.dll
    
  2. Compile e execute o código a seguir para enumerar os recursos no arquivo 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: {dict.Key}");
                try
                {
                    Console.WriteLine($"   Value: {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: {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: {binData}");
                    break;
                case "ResourceTypeCode.Int32":
                    Console.WriteLine($"   Recreated Value: {BitConverter.ToInt32(data, 0)}");
                    break;
                case "ResourceTypeCode.Boolean":
                    Console.WriteLine($"   Recreated Value: {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: {value1}");
                    break;
                default:
                    break;
            }
            Console.WriteLine();
        }
    }
    

    Depois de modificar o código-fonte (por exemplo, lançando deliberadamente um FormatException no final do bloco try), você pode executar o exemplo para ver como chamadas a GetResourceData permitem que você recupere ou recrie algumas informações de recurso.