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:
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.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.
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 blokusing
.
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