Classe System.Resources.ResourceReader

Questo articolo fornisce osservazioni supplementari alla documentazione di riferimento per questa API.

Importante

La chiamata a metodi da questa classe con dati non attendibili costituisce un rischio per la sicurezza. Chiamare i metodi da questa classe solo con dati attendibili. Per altre informazioni, vedere Convalidare tutti gli input.

La ResourceReader classe fornisce un'implementazione standard dell'interfaccia IResourceReader . Un'istanza ResourceReader di rappresenta un file con estensione resources autonomo o un file con estensione resources incorporato in un assembly. Viene usato per enumerare le risorse in un file con estensione resources e recuperare le coppie nome/valore. Differisce dalla ResourceManager classe , usata per recuperare le risorse denominate specificate da un file con estensione resources incorporato in un assembly. La ResourceManager classe viene usata per recuperare le risorse i cui nomi sono noti in anticipo, mentre la ResourceReader classe è utile per recuperare le risorse il cui numero o nomi precisi non sono noti in fase di compilazione. Ad esempio, un'applicazione può usare un file di risorse per archiviare le informazioni di configurazione organizzate in sezioni ed elementi in una sezione, in cui il numero di sezioni o elementi in una sezione non è noto in anticipo. Le risorse possono quindi essere denominate in modo generico (ad esempio Section1, Section1Item1, Section1Item2e così via) e recuperate usando un ResourceReader oggetto .

Importante

Il tipo implementa l'interfaccia IDisposable. Dopo aver utilizzato il tipo, è necessario eliminarlo direttamente o indirettamente. Per eliminare direttamente il tipo, chiamare il metodo Dispose in un blocco try/catch. Per eliminarlo indirettamente, utilizzare un costrutto di linguaggio come ad esempio using in C# o Using in Visual Basic. Per altre informazioni, vedere la sezione "Uso di un oggetto che implementa IDisposable" nella documentazione dell'interfaccia IDisposable .

Creare un'istanza di un oggetto ResourceReader

Un file con estensione resources è un file binario compilato da un file di testo o da un file con estensione resx XML Resgen.exe (Generatore di file di risorse). Un ResourceReader oggetto può rappresentare un file con estensione resources autonomo o un file con estensione resources incorporato in un assembly.

Per creare un'istanza di un ResourceReader oggetto che legge da un file con estensione resources autonomo, usare il costruttore della ResourceReader classe con un flusso di input o una stringa contenente il nome del file resources. Nell'esempio seguente vengono illustrati entrambi gli approcci. La prima crea un'istanza di un ResourceReader oggetto che rappresenta un file con estensione resources denominato Resources1.resources usando il relativo nome file. La seconda crea un'istanza di un ResourceReader oggetto che rappresenta un file con estensione resources denominato Resources2.resources usando un flusso creato dal file.

// 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)

Per creare un ResourceReader oggetto che rappresenta un file con estensione resources incorporato, creare un'istanza di un Assembly oggetto dall'assembly in cui è incorporato il file resources. Il Assembly.GetManifestResourceStream metodo restituisce un Stream oggetto che può essere passato al ResourceReader(Stream) costruttore. Nell'esempio seguente viene creata un'istanza di un ResourceReader oggetto che rappresenta un file con estensione resources incorporato.

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)

Enumerare le risorse di un oggetto ResourceReader

Per enumerare le risorse in un file con estensione resources, chiamare il GetEnumerator metodo , che restituisce un System.Collections.IDictionaryEnumerator oggetto . Chiamare il IDictionaryEnumerator.MoveNext metodo per passare da una risorsa alla successiva. Il metodo restituisce false quando tutte le risorse nel file con estensione resources sono state enumerate.

Nota

Anche se la ResourceReader classe implementa l'interfaccia IEnumerable e il IEnumerable.GetEnumerator metodo , il ResourceReader.GetEnumerator metodo non fornisce l'implementazione IEnumerable.GetEnumerator . Il metodo restituisce ResourceReader.GetEnumerator invece un IDictionaryEnumerator oggetto interfaccia che fornisce l'accesso alla coppia nome/valore di ogni risorsa.

È possibile recuperare le singole risorse nella raccolta in due modi:

  • È possibile eseguire l'iterazione di ogni risorsa nella System.Collections.IDictionaryEnumerator raccolta e usare System.Collections.IDictionaryEnumerator le proprietà per recuperare il nome e il valore della risorsa. È consigliabile usare questa tecnica quando tutte le risorse sono dello stesso tipo o si conosce il tipo di dati di ogni risorsa.

  • È possibile recuperare il nome di ogni risorsa quando si esegue l'iterazione della System.Collections.IDictionaryEnumerator raccolta e si chiama il GetResourceData metodo per recuperare i dati della risorsa. È consigliabile questo approccio quando non si conosce il tipo di dati di ogni risorsa o se l'approccio precedente genera eccezioni.

Recuperare le risorse usando le proprietà IDictionaryEnumerator

Il primo metodo di enumerazione delle risorse in un file con estensione resources comporta il recupero diretto della coppia nome/valore di ogni risorsa. Dopo aver chiamato il IDictionaryEnumerator.MoveNext metodo per passare a ogni risorsa nella raccolta, è possibile recuperare il nome della IDictionaryEnumerator.Key risorsa dalla proprietà e i dati della IDictionaryEnumerator.Value risorsa dalla proprietà .

Nell'esempio seguente viene illustrato come recuperare il nome e il valore di ogni risorsa in un file con estensione resources usando le IDictionaryEnumerator.Key proprietà e IDictionaryEnumerator.Value . Per eseguire l'esempio, creare il file di testo seguente denominato ApplicationResources.txt per definire le risorse stringa.

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

È quindi possibile convertire il file di risorse di testo in un file binario denominato ApplicationResources.resources usando il comando seguente:

resgen ApplicationResources.txt

Nell'esempio seguente viene quindi usata la ResourceReader classe per enumerare ogni risorsa nel file binario autonomo con estensione resources e per visualizzare il nome della chiave e il valore corrispondente.

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)

Il tentativo di recuperare i dati delle IDictionaryEnumerator.Value risorse dalla proprietà può generare le eccezioni seguenti:

  • Oggetto FormatException se i dati non sono nel formato previsto.
  • Oggetto FileNotFoundException se non è possibile trovare l'assembly contenente il tipo a cui appartengono i dati.
  • Oggetto TypeLoadException se non è possibile trovare il tipo a cui appartengono i dati.

In genere, queste eccezioni vengono generate se il file con estensione resources è stato modificato manualmente, se l'assembly in cui viene definito un tipo non è stato incluso in un'applicazione o è stato inavvertitamente eliminato o se l'assembly è una versione precedente che precede un tipo. Se viene generata una di queste eccezioni, è possibile recuperare le risorse enumerando ogni risorsa e chiamando il GetResourceData metodo , come illustrato nella sezione seguente. Questo approccio fornisce alcune informazioni sul tipo di dati che la IDictionaryEnumerator.Value proprietà ha tentato di restituire.

Recuperare le risorse in base al nome con GetResourceData

Il secondo approccio all'enumerazione delle risorse in un file con estensione resources comporta anche l'esplorazione delle risorse nel file chiamando il IDictionaryEnumerator.MoveNext metodo . Per ogni risorsa si recupera il nome della risorsa dalla IDictionaryEnumerator.Key proprietà , che viene quindi passata al GetResourceData(String, String, Byte[]) metodo per recuperare i dati della risorsa. Viene restituito come matrice di byte nell'argomento resourceData .

Questo approccio è più scomodo rispetto al recupero del nome e del valore della risorsa dalle IDictionaryEnumerator.Key proprietà e IDictionaryEnumerator.Value , perché restituisce i byte effettivi che formano il valore della risorsa. Tuttavia, se il tentativo di recuperare la risorsa genera un'eccezione, il GetResourceData metodo può aiutare a identificare l'origine dell'eccezione fornendo informazioni sul tipo di dati della risorsa. Per altre informazioni sulla stringa che indica il tipo di dati della risorsa, vedere GetResourceData.

Nell'esempio seguente viene illustrato come usare questo approccio per recuperare le risorse e per gestire eventuali eccezioni generate. Crea a livello di codice un file binario con estensione resources contenente quattro stringhe, un valore booleano, un numero intero e una bitmap. Per eseguire l'esempio, eseguire le operazioni seguenti:

  1. Compilare ed eseguire il codice sorgente seguente, che crea un file con estensione resources denominato 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();
            }
        }
    }
    

    Il file di codice sorgente è denominato CreateResources.cs. È possibile compilarlo in C# usando il comando seguente:

    csc CreateResources.cs /r:library.dll
    
  2. Compilare ed eseguire il codice seguente per enumerare le risorse nel file 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();
        }
    }
    

    Dopo aver modificato il codice sorgente (ad esempio, generando deliberatamente un oggetto FormatException alla fine del try blocco), è possibile eseguire l'esempio per vedere come le chiamate consentono GetResourceData di recuperare o ricreare alcune informazioni sulle risorse.