Bekerja dengan file .resx secara terprogram

Catatan

Artikel ini berlaku untuk .NET Framework. Untuk informasi yang berlaku untuk .NET 5+ (termasuk .NET Core), lihat Sumber daya di file .resx.

Karena file sumber daya XML (.resx) harus terdiri dari XML yang terdefinisi dengan baik, termasuk header yang harus mengikuti skema tertentu yang diikuti oleh data dalam pasangan nama/nilai, Anda mungkin menemukan bahwa membuat file ini secara manual dapat mengakibatkan terjadinya kesalahan. Sebagai alternatif, Anda dapat membuat file .resx secara terprogram dengan menggunakan jenis dan anggota di Pustaka kelas .NET. Anda juga dapat menggunakan Pustaka Kelas .NET untuk mengambil sumber daya yang disimpan dalam file .resx. Artikel ini menjelaskan bagaimana Anda bisa menggunakan jenis dan anggota di namespace System.Resources untuk bekerja dengan file .resx.

Artikel ini membahas bekerja dengan file XML (.resx) yang berisi sumber daya. Untuk informasi tentang bekerja dengan file sumber daya biner yang telah disematkan dalam rakitan, lihat ResourceManager.

Peringatan

Ada juga cara untuk bekerja dengan file .resx selain secara terprogram. Saat Anda menambahkan file sumber daya ke proyek Visual Studio, Visual Studio menyediakan antarmuka untuk membuat dan mempertahankan file .resx, dan secara otomatis mengonversi file .resx ke file .resources pada saat kompilasi. Anda juga dapat menggunakan editor teks untuk memanipulasi langsung file .resx. Tetapi, agar file tidak rusak, berhati-hatilah untuk tidak memodifikasi informasi biner yang disimpan dalam file.

Membuat file .resx

Anda dapat menggunakan kelas System.Resources.ResXResourceWriter untuk membuat file .resx secara terprogram, dengan mengikuti langkah-langkah berikut:

  1. Buat instans objek ResXResourceWriter dengan memanggil metode ResXResourceWriter(String) dan memberikan nama file .resx. Nama file harus menyertakan ekstensi .resx. Jika Anda membuat instans objek ResXResourceWriter dalam blok using, Anda tidak perlu secara eksplisit memanggil metode ResXResourceWriter.Close di langkah 3.

  2. Panggil metodeResXResourceWriter.AddResource untuk setiap sumber daya yang ingin Anda tambahkan ke file. Gunakan kelebihan beban metode ini untuk menambahkan data string, objek, dan biner (array byte). Jika sumber daya adalah objek, sumber daya harus dibuat berseri.

  3. Panggil metode ResXResourceWriter.Close untuk menghasilkan file sumber daya dan untuk merilis semua sumber daya. Jika objek ResXResourceWriter dibuat dalam blok using, sumber daya ditulis ke file .resx dan sumber daya yang digunakan oleh ResXResourceWriter objek dirilis di akhir blok using.

File .resx yang dihasilkan memiliki header dan tag data yang sesuai untuk setiap sumber daya yang ditambahkan oleh metode ResXResourceWriter.AddResource.

Peringatan

Jangan gunakan file sumber daya untuk menyimpan kata sandi, informasi yang sensitif keamanan, atau data privat.

Contoh berikut membuat file .resx bernama CarResources.resx yang menyimpan enam string, ikon, dan dua objek yang ditentukan aplikasi (dua objek Automobile). Kelas Automobile, yang didefinisikan dan dibuat instansnya dalam contoh, ditandai dengan atribut 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

Tip

Anda juga dapat menggunakan Visual Studio untuk membuat file .resx. Pada saat kompilasi, Visual Studio menggunakan Resource File Generator (Resgen.exe) untuk mengonversi file .resx ke file sumber daya biner (.resources), dan juga menyematkannya dalam rakitan aplikasi atau rakitan satelit.

Anda tidak dapat menyematkan file .resx dalam runtime yang dapat dieksekusi atau mengompilasinya ke dalam rakitan satelit. Anda harus mengonversi file .resx Anda menjadi file sumber daya biner (.resources) dengan menggunakan Resource File Generator (Resgen.exe). File .resources yang dihasilkan lalu dapat disematkan dalam rakitan aplikasi atau rakitan satelit. Untuk informasi selengkapnya, lihat Membuat sumber daya.

Menghitung sumber daya

Dalam beberapa kasus, Anda mungkin ingin mengambil semua sumber daya, alih-alih sumber daya tertentu, dari file .resx. Untuk melakukan ini, Anda dapat menggunakan kelas System.Resources.ResXResourceReader, yang menyediakan enumerator untuk semua sumber daya dalam file .resx. Kelas System.Resources.ResXResourceReader menerapkan IDictionaryEnumerator, yang mengembalikan DictionaryEntry objek yang merepresentasikan sumber daya tertentu untuk setiap iterasi perulangan. Properti DictionaryEntry.Key mengembalikan kunci sumber daya, dan properti DictionaryEntry.Value mengembalikan nilai sumber daya.

Contoh berikut membuat objek ResXResourceReader untuk file CarResources.resx yang dibuat dalam contoh sebelumnya dan melakukan iterasi melalui file sumber daya. Ini menambahkan dua objek Automobile yang didefinisikan dalam file sumber daya ke objek System.Collections.Generic.List<T>, dan menambahkan lima dari enam string ke objek SortedList. Nilai dalam objek SortedList dikonversi ke array parameter, yang digunakan untuk menampilkan judul kolom ke konsol. Nilai properti Automobile juga ditampilkan ke konsol.

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

Mengambil kebijakan tertentu

Selain menghitung item dalam file .resx, Anda dapat mengambil sumber daya tertentu berdasarkan nama dengan menggunakan kelas System.Resources.ResXResourceSet. Metode ResourceSet.GetString(String) ini mengambil nilai sumber daya string yang diberi nama. Metode ResourceSet.GetObject(String) mengambil nilai objek yang diberi nama atau data biner. Metode mengembalikan objek yang kemudian harus ditransmisikan (dalam C#) atau dikonversi (dalam Visual Basic) ke objek dari jenis yang sesuai.

Contoh berikut mengambil string keterangan formulir dan ikon dengan nama sumber dayanya. Ini juga mengambil objek yang ditentukan aplikasi Automobile yang digunakan dalam contoh sebelumnya dan menampilkannya dalam kontrol DataGridView.

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

Mengonversi file .resx ke file biner .resources

Mengonversi file .resx menjadi file sumber daya biner (.resources) yang disematkan memiliki manfaat yang besar. Meskipun file .resx mudah dibaca dan dipertahankan selama pengembangan aplikasi, file tersebut jarang disertakan dengan aplikasi yang sudah jadi. Jika didistribusikan dengan aplikasi, file .resx ada sebagai file terpisah selain dari aplikasi yang dapat dieksekusi dan pustaka yang menyertainya. Sebaliknya, file .resources disematkan dalam aplikasi yang dapat dieksekusi atau rakitan yang menyertainya. Selain itu, untuk aplikasi yang dilokalkan, mengandalkan file .resx pada durasi memberikan tanggung jawab untuk menangani fallback sumber daya pada pengembang. Sebaliknya, jika satu set rakitan satelit yang berisi file .resources tersemat telah dibuat, runtime bahasa umum akan menangani proses fallback sumber daya.

Untuk mengonversi file .resx ke file .resources, Anda menggunakan Resource File Generator (resgen.exe), yang memiliki sintaks dasar berikut:

 resgen.exe .resxFilename

Hasilnya adalah file sumber daya biner memiliki nama file akar yang sama dengan file .resx dan ekstensi file .resources. File ini lalu dapat dikompilasi ke dalam file yang dapat dieksekusi atau pustaka pada waktu kompilasi. Jika Anda menggunakan kompilator Visual Basic, gunakan sintaks berikut untuk menyematkan file .resources dalam aplikasi yang dapat dieksekusi:

vbc filename .vb -resource: .resourcesFilename

Jika Anda menggunakan C#, sintaksnya adalah sebagai berikut:

 csc filename .cs -resource: .resourcesFilename

File .resources juga dapat disematkan dalam rakitan satelit dengan menggunakan Assembly Linker (al.exe), ini memiliki sintaks dasar berikut:

al resourcesFilename -out: assemblyFilename

Lihat juga