Klasse System.Resources.ResourceReader

Notitie

In dit artikel vindt u aanvullende opmerkingen in de referentiedocumentatie voor deze API.

Belangrijk

Het aanroepen van methoden uit deze klasse met niet-vertrouwde gegevens is een beveiligingsrisico. Roep de methoden van deze klasse alleen aan met vertrouwde gegevens. Zie Alle invoergegevens validerenvoor meer informatie.

De ResourceReader-klasse biedt een standaard implementatie van de IResourceReader-interface. Een ResourceReader-exemplaar vertegenwoordigt een zelfstandig .resources-bestand of een .resources-bestand dat is ingesloten in een assembly. Het wordt gebruikt om de resources in een .resources-bestand op te sommen en de naam/waardeparen op te halen. Het verschilt van de ResourceManager-klasse, die wordt gebruikt om opgegeven benoemde resources op te halen uit een .resources-bestand dat is ingesloten in een assembly. De ResourceManager-klasse wordt gebruikt om resources op te halen waarvan de namen van tevoren bekend zijn, terwijl de ResourceReader klasse nuttig is voor het ophalen van resources waarvan het aantal of de exacte namen niet bekend zijn tijdens het compileren. Een toepassing kan bijvoorbeeld een resourcebestand gebruiken om configuratiegegevens op te slaan die zijn ingedeeld in secties en items in een sectie, waarbij het aantal secties of items in een sectie vooraf niet bekend is. Resources kunnen vervolgens algemeen worden genoemd (zoals Section1, Section1Item1, Section1Item2enzovoort) en worden opgehaald met behulp van een ResourceReader-object.

Belangrijk

Met dit type wordt de IDisposable interface geïmplementeerd. Wanneer u klaar bent met het gebruik van het type, moet u het direct of indirect verwijderen. Als u het type rechtstreeks wilt verwijderen, roept u de Dispose methode aan in een try/catch blok. Als u deze indirect wilt verwijderen, gebruikt u een taalconstructie zoals using (in C#) of Using (in Visual Basic). Zie de sectie 'Using an Object that Implements IDisposable' (Een object gebruiken dat IDisposable implementeert) in de IDisposable interfacedocumentatie voor meer informatie.

Een ResourceReader-object instantiëren

Een .resources-bestand is een binair bestand dat is gecompileerd vanuit een tekstbestand of een XML .resx-bestand door Resgen.exe (Resource File Generator). Een ResourceReader-object kan een zelfstandig .resources-bestand of een .resources-bestand vertegenwoordigen dat is ingesloten in een assembly.

Als u een ResourceReader-object wilt instantiëren dat wordt gelezen uit een zelfstandig .resources-bestand, gebruikt u de ResourceReader klasseconstructor met een invoerstroom of een tekenreeks die de bestandsnaam van de .resources bevat. In het volgende voorbeeld ziet u beide benaderingen. De eerste instantie instantieert een ResourceReader-object dat een .resources-bestand met de naam Resources1.resources vertegenwoordigt met behulp van de bestandsnaam. Met de tweede instantie wordt een ResourceReader-object geïnstitueerd dat een .resources-bestand met de naam Resources2.resources vertegenwoordigt met behulp van een stroom die is gemaakt op basis van het bestand.

// 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)

Als u een ResourceReader-object wilt maken dat een ingesloten .resources-bestand vertegenwoordigt, maakt u een exemplaar van een Assembly-object uit de assembly waarin het .resources-bestand is ingesloten. De Assembly.GetManifestResourceStream methode retourneert een Stream-object dat kan worden doorgegeven aan de ResourceReader(Stream) constructor. In het volgende voorbeeld wordt een ResourceReader-object geïnstitueert dat een ingesloten .resources-bestand vertegenwoordigt.

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)

Resources van een ResourceReader-object opsommen

Als u de resources in een .resources-bestand wilt inventariseren, roept u de methode GetEnumerator aan, die een System.Collections.IDictionaryEnumerator-object retourneert. U roept de IDictionaryEnumerator.MoveNext methode aan om van de ene resource naar de volgende te gaan. De methode retourneert false wanneer alle resources in het .resources-bestand zijn geïnventariseerd.

Notitie

Hoewel de ResourceReader-klasse de IEnumerable-interface en de methode IEnumerable.GetEnumerator implementeert, biedt de ResourceReader.GetEnumerator methode niet de IEnumerable.GetEnumerator-implementatie. In plaats daarvan retourneert de methode ResourceReader.GetEnumerator een IDictionaryEnumerator interfaceobject dat toegang biedt tot het naam-/waardepaar van elke resource.

U kunt de afzonderlijke resources in de verzameling op twee manieren ophalen:

Resources ophalen met behulp van IDictionaryEnumerator-eigenschappen

De eerste methode voor het inventariseren van de resources in een .resources-bestand omvat het rechtstreeks ophalen van de naam/waardepaar van elke resource. Nadat u de IDictionaryEnumerator.MoveNext methode hebt aangeroepen om naar elke resource in de verzameling te gaan, kunt u de resourcenaam ophalen uit de eigenschap IDictionaryEnumerator.Key en de resourcegegevens uit de eigenschap IDictionaryEnumerator.Value.

In het volgende voorbeeld ziet u hoe u de naam en waarde van elke resource in een .resources-bestand ophaalt met behulp van de eigenschappen IDictionaryEnumerator.Key en IDictionaryEnumerator.Value. Als u het voorbeeld wilt uitvoeren, maakt u het volgende tekstbestand met de naam ApplicationResources.txt om tekenreeksbronnen te definiëren.

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:"

Vervolgens kunt u het tekstbestand converteren naar een binair bestand met de naam ApplicationResources.resources met behulp van de volgende opdracht:

resgen ApplicationResources.txt

In het volgende voorbeeld wordt vervolgens de klasse ResourceReader gebruikt om elke resource in het zelfstandige binaire .resources-bestand op te sommen en de sleutelnaam en de bijbehorende waarde weer te geven.

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($"   {dict.Key}: '{dict.Value}' (Type {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)

De poging om resourcegegevens op te halen uit de eigenschap IDictionaryEnumerator.Value kan de volgende uitzonderingen genereren:

  • Een FormatException als de gegevens niet de verwachte indeling hebben.
  • Een FileNotFoundException als de assembly die het type bevat waartoe de gegevens behoren, niet kan worden gevonden.
  • Een TypeLoadException wanneer het type waartoe de gegevens behoren niet gevonden kan worden.

Deze uitzonderingen worden meestal gegenereerd als het .resources-bestand handmatig is gewijzigd, als de assembly waarin een type is gedefinieerd, niet is opgenomen in een toepassing of per ongeluk is verwijderd, of als de assembly een oudere versie is die voorafgaat aan een type. Als een van deze uitzonderingen optreedt, kunt u resources ophalen door elke resource op te sommen en de GetResourceData methode aan te roepen, zoals in de volgende sectie wordt weergegeven. Deze benadering biedt u informatie over het gegevenstype dat de IDictionaryEnumerator.Value eigenschap heeft geprobeerd te retourneren.

Resources ophalen op naam met GetResourceData

De tweede benadering voor het inventariseren van resources in een .resources-bestand omvat ook het navigeren door de resources in het bestand door de IDictionaryEnumerator.MoveNext methode aan te roepen. Voor elke resource haalt u de naam van de resource op uit de eigenschap IDictionaryEnumerator.Key, die vervolgens wordt doorgegeven aan de GetResourceData(String, String, Byte[]) methode om de gegevens van de resource op te halen. Dit wordt geretourneerd als een bytematrix in het argument resourceData.

Deze benadering is omslachtiger dan het ophalen van de resourcenaam en -waarde uit de eigenschappen IDictionaryEnumerator.Key en IDictionaryEnumerator.Value, omdat deze de werkelijke bytes retourneert die de resourcewaarde vormen. Als de poging om de resource op te halen echter een uitzondering genereert, kan de GetResourceData methode helpen de bron van de uitzondering te identificeren door informatie op te geven over het gegevenstype van de resource. Zie GetResourceDatavoor meer informatie over de tekenreeks die het gegevenstype van de resource aangeeft.

In het volgende voorbeeld ziet u hoe u deze benadering gebruikt om middelen op te halen en om te gaan met eventuele uitzonderingen die worden opgeworpen. Er wordt programmatisch een binair .resources-bestand gemaakt dat vier tekenreeksen, één Booleaanse waarde, één geheel getal en één bitmap bevat. Ga als volgt te werk om het voorbeeld uit te voeren:

  1. Compileer en voer de volgende broncode uit, waarmee een .resources-bestand met de naam ContactResources.resources wordt gemaakt.

    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();
            }
        }
    }
    

    Het broncodebestand heeft de naam CreateResources.cs. U kunt deze compileren in C# met behulp van de volgende opdracht:

    csc CreateResources.cs /r:library.dll
    
  2. Compileer en voer de volgende code uit om de resources in het bestand ContactResources.resources op te sommen.

    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: {dict.Key}");
                try
                {
                    Console.WriteLine($"   Value: {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: {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: {binData}");
                    break;
                case "ResourceTypeCode.Int32":
                    Console.WriteLine($"   Recreated Value: {BitConverter.ToInt32(data, 0)}");
                    break;
                case "ResourceTypeCode.Boolean":
                    Console.WriteLine($"   Recreated Value: {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: {value1}");
                    break;
                default:
                    break;
            }
            Console.WriteLine();
        }
    }
    

    Nadat u de broncode hebt gewijzigd (bijvoorbeeld door opzettelijk een FormatException aan het einde van het try blok te genereren), kunt u het voorbeeld uitvoeren om te zien hoe aanroepen naar GetResourceData u in staat stelt om bepaalde resourcegegevens op te halen of opnieuw te maken.