Condividi tramite


Usare i file con estensione .resx in modo programmatico

Annotazioni

Questo articolo si applica a .NET Framework. Per informazioni che si applicano a .NET 5+ (incluso .NET Core), vedere Risorse nei file resx.

Poiché i file di risorse XML (con estensione resx) devono essere costituiti da xml ben definiti, inclusa un'intestazione che deve seguire uno schema specifico seguito dai dati nelle coppie nome/valore, è possibile che la creazione di questi file manualmente sia soggetta a errori. In alternativa, è possibile creare file resx a livello di codice usando tipi e membri nella libreria di classi .NET. È anche possibile usare la libreria di classi .NET per recuperare le risorse archiviate nei file resx. Questo articolo illustra come usare i tipi e i membri nello System.Resources spazio dei nomi per usare i file resx.

Questo articolo illustra l'uso di file XML (con estensione resx) che contengono risorse. Per informazioni sull'uso dei file di risorse binari che sono stati incorporati negli assembly, vedere ResourceManager.

Avvertimento

Esistono anche modi per usare file con estensione resx diversi da quelli a livello di codice. Quando si aggiunge un file di risorse a un progetto di Visual Studio , Visual Studio fornisce un'interfaccia per la creazione e la gestione di un file resx e converte automaticamente il file resx in un file con estensione resources in fase di compilazione. È anche possibile usare un editor di testo per modificare direttamente un file con estensione resx. Tuttavia, per evitare di danneggiare il file, prestare attenzione a non modificare le informazioni binarie archiviate nel file.

Creare un file resx

È possibile usare la System.Resources.ResXResourceWriter classe per creare un file con estensione resx a livello di codice, seguendo questa procedura:

  1. Creare un'istanza di un ResXResourceWriter oggetto chiamando il ResXResourceWriter(String) metodo e specificando il nome del file resx. Il nome del file deve includere l'estensione resx. Se si crea un'istanza dell'oggetto ResXResourceWriter in un blocco using, non è necessario chiamare esplicitamente il metodo ResXResourceWriter.Close nel passaggio 3.

  2. Chiamare il ResXResourceWriter.AddResource metodo per ogni risorsa da aggiungere al file. Usare gli overload di questo metodo per aggiungere dati di tipo stringa, dati di tipo oggetto e dati binari (matrice di byte). Se la risorsa è un oggetto, deve essere serializzabile.

  3. Chiamare il ResXResourceWriter.Close metodo per generare il file di risorse e rilasciare tutte le risorse. Se l'oggetto ResXResourceWriter è stato creato all'interno di un using blocco, le risorse vengono scritte nel file resx e le risorse usate dall'oggetto ResXResourceWriter vengono rilasciate alla fine del using blocco.

Il file con estensione resx risultante ha l'intestazione appropriata e un data tag per ogni risorsa aggiunta dal ResXResourceWriter.AddResource metodo .

Avvertimento

Non usare file di risorse per archiviare password, informazioni sensibili per la sicurezza o dati personali.

Nell'esempio seguente viene creato un file resx denominato CarResources.resx che archivia sei stringhe, un'icona e due oggetti definiti dall'applicazione (due Automobile oggetti). La Automobile classe , definita e creata nell'esempio, viene contrassegnata con l'attributo SerializableAttribute .

using System;
using System.Drawing;
using System.Resources;

[Serializable()] public class Automobile
{
   private string carMake;
   private string carModel;
   private int carYear;
   private int carDoors;
   private int carCylinders;

   public Automobile(string make, string model, int year) :
                     this(make, model, year, 0, 0)
   { }

   public Automobile(string make, string model, int year,
                     int doors, int cylinders)
   {
      this.carMake = make;
      this.carModel = model;
      this.carYear = year;
      this.carDoors = doors;
      this.carCylinders = cylinders;
   }

   public string Make {
      get { return this.carMake; }
   }

   public string Model {
      get {return this.carModel; }
   }

   public int Year {
      get { return this.carYear; }
   }

   public int Doors {
      get { return this.carDoors; }
   }

   public int Cylinders {
      get { return this.carCylinders; }
   }
}

public class Example
{
   public static void Main()
   {
      // Instantiate an Automobile object.
      Automobile car1 = new Automobile("Ford", "Model N", 1906, 0, 4);
      Automobile car2 = new Automobile("Ford", "Model T", 1909, 2, 4);
      // Define a resource file named CarResources.resx.
      using (ResXResourceWriter resx = new ResXResourceWriter(@".\CarResources.resx"))
      {
         resx.AddResource("Title", "Classic American Cars");
         resx.AddResource("HeaderString1", "Make");
         resx.AddResource("HeaderString2", "Model");
         resx.AddResource("HeaderString3", "Year");
         resx.AddResource("HeaderString4", "Doors");
         resx.AddResource("HeaderString5", "Cylinders");
         resx.AddResource("Information", SystemIcons.Information);
         resx.AddResource("EarlyAuto1", car1);
         resx.AddResource("EarlyAuto2", car2);
      }
   }
}
Imports System.Drawing
Imports System.Resources

<Serializable()> Public Class Automobile
    Private carMake As String
    Private carModel As String
    Private carYear As Integer
    Private carDoors AS Integer
    Private carCylinders As Integer

    Public Sub New(make As String, model As String, year As Integer)
        Me.New(make, model, year, 0, 0)
    End Sub

    Public Sub New(make As String, model As String, year As Integer,
                   doors As Integer, cylinders As Integer)
        Me.carMake = make
        Me.carModel = model
        Me.carYear = year
        Me.carDoors = doors
        Me.carCylinders = cylinders
    End Sub

    Public ReadOnly Property Make As String
        Get
            Return Me.carMake
        End Get
    End Property

    Public ReadOnly Property Model As String
        Get
            Return Me.carModel
        End Get
    End Property

    Public ReadOnly Property Year As Integer
        Get
            Return Me.carYear
        End Get
    End Property

    Public ReadOnly Property Doors As Integer
        Get
            Return Me.carDoors
        End Get
    End Property

    Public ReadOnly Property Cylinders As Integer
        Get
            Return Me.carCylinders
        End Get
    End Property
End Class

Module Example
    Public Sub Main()
        ' Instantiate an Automobile object.
        Dim car1 As New Automobile("Ford", "Model N", 1906, 0, 4)
        Dim car2 As New Automobile("Ford", "Model T", 1909, 2, 4)
        ' Define a resource file named CarResources.resx.
        Using resx As New ResXResourceWriter(".\CarResources.resx")
            resx.AddResource("Title", "Classic American Cars")
            resx.AddResource("HeaderString1", "Make")
            resx.AddResource("HeaderString2", "Model")
            resx.AddResource("HeaderString3", "Year")
            resx.AddResource("HeaderString4", "Doors")
            resx.AddResource("HeaderString5", "Cylinders")
            resx.AddResource("Information", SystemIcons.Information)
            resx.AddResource("EarlyAuto1", car1)
            resx.AddResource("EarlyAuto2", car2)
        End Using
    End Sub
End Module

Suggerimento

È anche possibile usare Visual Studio per creare file resx. In fase di compilazione, Visual Studio usa il generatore di file di risorse (Resgen.exe) per convertire il file resx in un file di risorse binarie (con estensione resources) e lo incorpora anche in un assembly dell'applicazione o in un assembly satellite.

Non è possibile incorporare un file resx in un eseguibile di runtime o compilarlo in un assembly satellite. È necessario convertire il file con estensione resx in un file di risorse binarie (con estensione resources) usando il generatore di file di risorse (Resgen.exe). Il file .resources risultante può quindi essere incorporato in un assembly dell'applicazione o in un assembly satellite. Per altre informazioni, vedere Creare file di risorse.

Enumerare le risorse

In alcuni casi, è possibile recuperare tutte le risorse, anziché una risorsa specifica, da un file resx. A tale scopo, è possibile usare la System.Resources.ResXResourceReader classe , che fornisce un enumeratore per tutte le risorse nel file resx. La System.Resources.ResXResourceReader classe implementa , che restituisce IDictionaryEnumeratorun DictionaryEntry oggetto che rappresenta una determinata risorsa per ogni iterazione del ciclo. La DictionaryEntry.Key proprietà restituisce la chiave della risorsa e la relativa DictionaryEntry.Value proprietà restituisce il valore della risorsa.

L'esempio seguente crea un oggetto ResXResourceReader associato al file CarResources.resx generato nell'esempio precedente e itera attraverso il file delle risorse. Aggiunge i due Automobile oggetti definiti nel file di risorse a un System.Collections.Generic.List<T> oggetto e aggiunge cinque delle sei stringhe a un SortedList oggetto . I valori nell'oggetto SortedList vengono convertiti in una matrice di parametri, che viene usata per visualizzare le intestazioni di colonna nella console. I valori delle Automobile proprietà vengono visualizzati anche nella console.

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

public class Example
{
   public static void Main()
   {
      string resxFile = @".\CarResources.resx";
      List<Automobile> autos = new List<Automobile>();
      SortedList headers = new SortedList();

      using (ResXResourceReader resxReader = new ResXResourceReader(resxFile))
      {
         foreach (DictionaryEntry entry in resxReader) {
            if (((string) entry.Key).StartsWith("EarlyAuto"))
               autos.Add((Automobile) entry.Value);
            else if (((string) entry.Key).StartsWith("Header"))
               headers.Add((string) entry.Key, (string) entry.Value);
         }
      }
      string[] headerColumns = new string[headers.Count];
      headers.GetValueList().CopyTo(headerColumns, 0);
      Console.WriteLine("{0,-8} {1,-10} {2,-4}   {3,-5}   {4,-9}\n",
                        headerColumns);
      foreach (var auto in autos)
         Console.WriteLine("{0,-8} {1,-10} {2,4}   {3,5}   {4,9}",
                           auto.Make, auto.Model, auto.Year,
                           auto.Doors, auto.Cylinders);
   }
}
// The example displays the following output:
//       Make     Model      Year   Doors   Cylinders
//
//       Ford     Model N    1906       0           4
//       Ford     Model T    1909       2           4
Imports System.Collections
Imports System.Collections.Generic
Imports System.Resources

Module Example
    Public Sub Main()
        Dim resxFile As String = ".\CarResources.resx"
        Dim autos As New List(Of Automobile)
        Dim headers As New SortedList()

        Using resxReader As New ResXResourceReader(resxFile)
            For Each entry As DictionaryEntry In resxReader
                If CType(entry.Key, String).StartsWith("EarlyAuto") Then
                    autos.Add(CType(entry.Value, Automobile))
                Else If CType(entry.Key, String).StartsWith("Header") Then
                    headers.Add(CType(entry.Key, String), CType(entry.Value, String))
                End If
            Next
        End Using
        Dim headerColumns(headers.Count - 1) As String
        headers.GetValueList().CopyTo(headerColumns, 0)
        Console.WriteLine("{0,-8} {1,-10} {2,-4}   {3,-5}   {4,-9}",
                          headerColumns)
        Console.WriteLine()
        For Each auto In autos
            Console.WriteLine("{0,-8} {1,-10} {2,4}   {3,5}   {4,9}",
                              auto.Make, auto.Model, auto.Year,
                              auto.Doors, auto.Cylinders)
        Next
    End Sub
End Module
' The example displays the following output:
'       Make     Model      Year   Doors   Cylinders
'       
'       Ford     Model N    1906       0           4
'       Ford     Model T    1909       2           4

Recuperare una risorsa specifica

Oltre a enumerare gli elementi in un file con estensione resx, è possibile recuperare una risorsa specifica in base al nome usando la System.Resources.ResXResourceSet classe . Il ResourceSet.GetString(String) metodo recupera il valore di una risorsa stringa denominata. Il ResourceSet.GetObject(String) metodo recupera il valore di un oggetto denominato o di dati binari. Il metodo restituisce un oggetto che deve essere effettuato il cast (in C#) o convertito (in Visual Basic) in un oggetto del tipo appropriato.

Nell'esempio seguente viene recuperata la stringa e l'icona della didascalia di un modulo in base ai nomi delle risorse. Recupera anche gli oggetti definiti dall'applicazione Automobile usati nell'esempio precedente e li visualizza in un DataGridView controllo .

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Resources;
using System.Windows.Forms;

public class CarDisplayApp : Form
{
   private const string resxFile = @".\CarResources.resx";
   Automobile[] cars;

   public static void Main()
   {
      CarDisplayApp app = new CarDisplayApp();
      Application.Run(app);
   }

   public CarDisplayApp()
   {
      // Instantiate controls.
      PictureBox pictureBox = new PictureBox();
      pictureBox.Location = new Point(10, 10);
      this.Controls.Add(pictureBox);
      DataGridView grid = new DataGridView();
      grid.Location = new Point(10, 60);
      this.Controls.Add(grid);

      // Get resources from .resx file.
      using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
      {
         // Retrieve the string resource for the title.
         this.Text = resxSet.GetString("Title");
         // Retrieve the image.
         Icon image = (Icon) resxSet.GetObject("Information", true);
         if (image != null)
            pictureBox.Image = image.ToBitmap();

         // Retrieve Automobile objects.
         List<Automobile> carList = new List<Automobile>();
         string resName = "EarlyAuto";
         Automobile auto;
         int ctr = 1;
         do {
            auto = (Automobile) resxSet.GetObject(resName + ctr.ToString());
            ctr++;
            if (auto != null)
               carList.Add(auto);
         } while (auto != null);
         cars = carList.ToArray();
         grid.DataSource = cars;
      }
   }
}
Imports System.Collections.Generic
Imports System.Drawing
Imports System.Resources
Imports System.Windows.Forms

Public Class CarDisplayApp : Inherits Form
    Private Const resxFile As String = ".\CarResources.resx"
    Dim cars() As Automobile

    Public Shared Sub Main()
        Dim app As New CarDisplayApp()
        Application.Run(app)
    End Sub

    Public Sub New()
        ' Instantiate controls.
        Dim pictureBox As New PictureBox()
        pictureBox.Location = New Point(10, 10)
        Me.Controls.Add(pictureBox)
        Dim grid As New DataGridView()
        grid.Location = New Point(10, 60)
        Me.Controls.Add(grid)

        ' Get resources from .resx file.
        Using resxSet As New ResXResourceSet(resxFile)
            ' Retrieve the string resource for the title.
            Me.Text = resxSet.GetString("Title")
            ' Retrieve the image.
            Dim image As Icon = CType(resxSet.GetObject("Information", True), Icon)
            If image IsNot Nothing Then
                pictureBox.Image = image.ToBitmap()
            End If

            ' Retrieve Automobile objects.  
            Dim carList As New List(Of Automobile)
            Dim resName As String = "EarlyAuto"
            Dim auto As Automobile
            Dim ctr As Integer = 1
            Do
                auto = CType(resxSet.GetObject(resName + ctr.ToString()), Automobile)
                ctr += 1
                If auto IsNot Nothing Then carList.Add(auto)
            Loop While auto IsNot Nothing
            cars = carList.ToArray()
            grid.DataSource = cars
        End Using
    End Sub
End Class

Convertire i file resx in file binari con estensione resources

La conversione di file con estensione .resx in file di risorse binarie incorporate (.resources) presenta vantaggi significativi. Anche se i file resx sono facili da leggere e gestire durante lo sviluppo di applicazioni, raramente vengono inclusi nelle applicazioni completate. Se vengono distribuiti con un'applicazione, esistono come file separati dall'eseguibile dell'applicazione e dalle librerie associate. Al contrario, i file .resources sono incorporati nell'eseguibile dell'applicazione o nei suoi assembly associati. Inoltre, per le applicazioni localizzate, l'uso di file resx in fase di esecuzione pone la responsabilità di gestire il fallback delle risorse nello sviluppatore. Al contrario, se è stato creato un set di assembly satellite che contengono file .resources incorporati, il common language runtime gestisce il processo di fallback delle risorse.

Per convertire un file con estensione resx in un file con estensione resources, usare Generatore di file di risorse (resgen.exe), con la sintassi di base seguente:

 resgen.exe .resxFilename

Il risultato è un file di risorse binario con lo stesso nome di file radice del file .resx e un'estensione di file .resources. Questo file può quindi essere compilato in un eseguibile o in una libreria in fase di compilazione. Se si usa il compilatore Visual Basic, usare la sintassi seguente per incorporare un file con estensione resources nell'eseguibile di un'applicazione:

vbc filename .vb -resource: .resourcesFilename

Se si usa C#, la sintassi è la seguente:

 csc filename .cs -resource: .resourcesFilename

Il file con estensione resources può anche essere incorporato in un assembly satellite usando Assembly Linker (al.exe), con la sintassi di base seguente:

al resourcesFilename -out: assemblyFilename

Vedere anche