System.Resources.ResourceReader, klasa
Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.
Ważne
Wywoływanie metod z tej klasy z niezaufanymi danymi jest zagrożeniem bezpieczeństwa. Wywołaj metody z tej klasy tylko z zaufanymi danymi. Aby uzyskać więcej informacji, zobacz Validate All Inputs (Weryfikowanie wszystkich danych wejściowych).
Klasa ResourceReader zapewnia standardową implementację interfejsu IResourceReader . Wystąpienie ResourceReader reprezentuje autonomiczny plik resources lub plik resources osadzony w zestawie. Służy do wyliczania zasobów w pliku resources i pobierania par nazwa/wartość. Różni się ona od ResourceManager klasy , która jest używana do pobierania określonych nazwanych zasobów z pliku resources, który jest osadzony w zestawie. Klasa służy do pobierania ResourceManager zasobów, których nazwy są znane z wyprzedzeniem, podczas gdy ResourceReader klasa jest przydatna do pobierania zasobów, których liczba lub dokładne nazwy nie są znane w czasie kompilacji. Na przykład aplikacja może używać pliku zasobów do przechowywania informacji o konfiguracji zorganizowanych w sekcjach i elementach w sekcji, gdzie liczba sekcji lub elementów w sekcji nie jest znana z wyprzedzeniem. Następnie zasoby mogą być nazwane ogólnie (na przykład Section1
, Section1Item1
, Section1Item2
i tak dalej) i pobierane przy użyciu ResourceReader obiektu.
Ważne
Ten typ implementuje IDisposable interfejs. Po zakończeniu korzystania z typu należy usunąć go bezpośrednio lub pośrednio. Aby usunąć typ bezpośrednio, wywołaj metodę Disposetry
/catch
w bloku. Aby usunąć go pośrednio, należy użyć konstrukcji języka, takiej jak using
(w języku C#) lub Using
(w Visual Basic). Aby uzyskać więcej informacji, zobacz sekcję "Using an Object that Implements IDisposable" (Używanie obiektu implementujące interfejs IDisposable) w dokumentacji interfejsu IDisposable .
Tworzenie wystąpienia obiektu ResourceReader
Plik resources jest plikiem binarnym, który został skompilowany z pliku tekstowego lub pliku RESX XML przez Resgen.exe (Generator plików zasobów). ResourceReader Obiekt może reprezentować autonomiczny plik resources lub plik resources, który został osadzony w zestawie.
Aby utworzyć ResourceReader wystąpienie obiektu, który odczytuje z autonomicznego pliku resources, użyj ResourceReader konstruktora klasy ze strumieniem wejściowym lub ciągiem zawierającym nazwę pliku resources. Poniższy przykład ilustruje oba podejścia. Pierwsze wystąpienie ResourceReader obiektu reprezentującego plik resources o nazwie Resources1.resources
przy użyciu jego nazwy pliku. Drugie wystąpienie ResourceReader obiektu reprezentującego plik resources o nazwie Resources2.resources
przy użyciu strumienia utworzonego na podstawie pliku.
// 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)
Aby utworzyć ResourceReader obiekt reprezentujący osadzony plik resources, utwórz wystąpienie Assembly obiektu z zestawu, w którym osadzony jest plik resources. Metoda Assembly.GetManifestResourceStream zwraca Stream obiekt, który można przekazać do konstruktora ResourceReader(Stream) . Poniższy przykład tworzy wystąpienie ResourceReader obiektu reprezentującego osadzony plik resources.
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)
Wyliczanie zasobów obiektu ResourceReader
Aby wyliczyć zasoby w pliku resources, należy wywołać GetEnumerator metodę , która zwraca System.Collections.IDictionaryEnumerator obiekt. Wywołasz metodę IDictionaryEnumerator.MoveNext
, aby przejść z jednego zasobu do następnego. Metoda zwraca false
, gdy wszystkie zasoby w pliku resources zostały wyliczone.
Uwaga
ResourceReader Mimo że klasa implementuje IEnumerable interfejs i IEnumerable.GetEnumerator metodę, ResourceReader.GetEnumerator metoda nie zapewnia implementacjiIEnumerable.GetEnumerator. ResourceReader.GetEnumerator Zamiast tego metoda zwraca obiekt interfejsuIDictionaryEnumerator, który zapewnia dostęp do pary nazw/wartości każdego zasobu.
Poszczególne zasoby można pobrać w kolekcji na dwa sposoby:
Każdy zasób można iterować w System.Collections.IDictionaryEnumerator kolekcji i używać System.Collections.IDictionaryEnumerator właściwości, aby pobrać nazwę i wartość zasobu. Zalecamy tę technikę, gdy wszystkie zasoby są tego samego typu lub znasz typ danych każdego zasobu.
Nazwę każdego zasobu można pobrać podczas iteracji System.Collections.IDictionaryEnumerator kolekcji i wywołać metodę GetResourceData w celu pobrania danych zasobu. Zalecamy takie podejście, jeśli nie znasz typu danych każdego zasobu lub jeśli poprzednie podejście zgłasza wyjątki.
Pobieranie zasobów przy użyciu właściwości IDictionaryEnumerator
Pierwsza metoda wyliczania zasobów w pliku resources obejmuje bezpośrednie pobieranie pary nazw/wartości każdego zasobu. Po wywołaniu IDictionaryEnumerator.MoveNext
metody , aby przejść do każdego zasobu w kolekcji, możesz pobrać nazwę zasobu z IDictionaryEnumerator.Key właściwości i dane zasobów z IDictionaryEnumerator.Value właściwości.
W poniższym przykładzie pokazano, jak pobrać nazwę i wartość każdego zasobu w pliku resources przy użyciu właściwości IDictionaryEnumerator.Key i IDictionaryEnumerator.Value . Aby uruchomić przykład, utwórz następujący plik tekstowy o nazwie ApplicationResources.txt w celu zdefiniowania zasobów ciągów.
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:"
Następnie możesz przekonwertować plik zasobu tekstowego na plik binarny o nazwie ApplicationResources.resources przy użyciu następującego polecenia:
resgen ApplicationResources.txt
W poniższym przykładzie użyto ResourceReader klasy , aby wyliczyć każdy zasób w autonomicznym pliku zasobów binarnych i wyświetlić jego nazwę klucza i odpowiadającą mu wartość.
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)
Próba pobrania danych zasobów z IDictionaryEnumerator.Value właściwości może zgłaszać następujące wyjątki:
- A FormatException jeśli dane nie mają oczekiwanego formatu.
- Jeśli FileNotFoundException nie można odnaleźć zestawu zawierającego typ, do którego należą dane.
- Jeśli TypeLoadException nie można odnaleźć typu, do którego należą dane.
Zazwyczaj te wyjątki są zgłaszane, jeśli plik resources został zmodyfikowany ręcznie, jeśli zestaw, w którym zdefiniowano typ, nie został dołączony do aplikacji lub został przypadkowo usunięty lub jeśli zestaw jest starszą wersją, która poprzedza typ. Jeśli zostanie zgłoszony jeden z tych wyjątków, możesz pobrać zasoby, wyliczając każdy zasób i wywołując metodę GetResourceData , jak pokazano w poniższej sekcji. Takie podejście zapewnia pewne informacje o typie danych, które IDictionaryEnumerator.Value właściwość próbowała zwrócić.
Pobieranie zasobów według nazwy za pomocą polecenia GetResourceData
Drugie podejście do wyliczania zasobów w pliku resources obejmuje również nawigowanie po zasobach w pliku przez wywołanie IDictionaryEnumerator.MoveNext
metody . Dla każdego zasobu pobierasz nazwę zasobu z IDictionaryEnumerator.Key właściwości , która jest następnie przekazywana do GetResourceData(String, String, Byte[]) metody w celu pobrania danych zasobu. Jest to zwracane jako tablica bajtów w argumencie resourceData
.
Takie podejście jest bardziej niezręczne niż pobieranie nazwy i wartości zasobu z IDictionaryEnumerator.Key właściwości i IDictionaryEnumerator.Value , ponieważ zwraca rzeczywiste bajty, które tworzą wartość zasobu. Jeśli jednak próba pobrania zasobu zgłosi wyjątek, GetResourceData metoda może pomóc zidentyfikować źródło wyjątku, podając informacje o typie danych zasobu. Aby uzyskać więcej informacji o ciągu wskazującym typ danych zasobu, zobacz GetResourceData.
Poniższy przykład ilustruje sposób użycia tego podejścia do pobierania zasobów i obsługi wszelkich zgłaszanych wyjątków. Programowo tworzy binarny plik resources zawierający cztery ciągi, jedną wartość logiczną, jedną liczbę całkowitą i jedną mapę bitową. Aby uruchomić przykład, wykonaj następujące czynności:
Skompiluj i wykonaj następujący kod źródłowy, który tworzy plik resources o nazwie 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(); } } }
Plik kodu źródłowego nosi nazwę CreateResources.cs. Można go skompilować w języku C#, używając następującego polecenia:
csc CreateResources.cs /r:library.dll
Skompiluj i uruchom następujący kod, aby wyliczyć zasoby w pliku 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(); } }
Po zmodyfikowaniu kodu źródłowego (na przykład przez celowe zgłoszenie FormatException elementu na końcu
try
bloku) możesz uruchomić przykład, aby zobaczyć, jak wywołania GetResourceData umożliwiają pobieranie lub ponowne tworzenie informacji o zasobie.