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, Section1Item2i 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:

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:

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:

  1. 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
    
  2. 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.