Класс System.Resources.ResourceReader

В этой статье приводятся дополнительные замечания к справочной документации по этому API.

Важно!

Вызов методов этого класса для ненадежных данных представляет угрозу безопасности. Вызывайте методы класса только для надежных данных. Дополнительные сведения см. в разделе "Проверка всех входных данных".

Класс ResourceReader предоставляет стандартную реализацию IResourceReader интерфейса. ResourceReader Экземпляр представляет автономный файл ресурсов или файл .resources, внедренный в сборку. Он используется для перечисления ресурсов в файле ресурсов и получения пар "имя-значение". Он отличается от ResourceManager класса, который используется для извлечения указанных именованных ресурсов из файла РЕСУРСОВ, внедренного в сборку. Класс ResourceManager используется для получения ресурсов, имена которых известны заранее, в то время как ResourceReader класс полезен для получения ресурсов, число или точные имена которых не известны во время компиляции. Например, приложение может использовать файл ресурсов для хранения сведений о конфигурации, организованных в разделах и элементах в разделе, где количество разделов или элементов в разделе неизвестно заранее. Затем ресурсы могут называться универсально (напримерSection1, , Section1Item1Section1Item2и т. д.) и извлекаться с помощью ResourceReader объекта.

Важно!

Этот тип реализует интерфейс IDisposable. По окончании использования выдаленную ему память следует прямо или косвенно освободить. Чтобы сделать это прямо, вызовите его метод Dispose в блоке try/catch. Чтобы сделать это косвенно, используйте языковые конструкции, такие как using (в C#) или Using (в Visual Basic). Дополнительные сведения см. в разделе "Использование объекта, реализующего IDisposable" в документации по интерфейсу IDisposable .

Создание экземпляра объекта ResourceReader

Файл ресурсов — это двоичный файл, скомпилированный из текстового файла или XML-RESX-файла Resgen.exe (генератор файлов ресурсов). ResourceReader Объект может представлять автономный файл .resources или файл .resources, внедренный в сборку.

Чтобы создать экземпляр ResourceReader объекта, который считывается из автономного файла ресурсов, используйте ResourceReader конструктор класса с входным потоком или строкой, содержащей имя файла .resources. В следующем примере показаны оба подхода. Первый создает экземпляр ResourceReader объекта, представляющего файл ресурсов с именем Resources1.resources файла с именем файла. Второй создает экземпляр ResourceReader объекта, представляющего файл ресурсов с именем Resources2.resources с помощью потока, созданного из файла.

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

Чтобы создать объект, представляющий внедренный файл ресурсов, создайте ResourceReaderAssembly экземпляр объекта из сборки, в которой внедрен файл resources. Его Assembly.GetManifestResourceStream метод возвращает Stream объект, который можно передать конструктору ResourceReader(Stream) . В следующем примере создается ResourceReader экземпляр объекта, представляющего внедренный файл ресурсов.

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)

Перечисление ресурсов объекта ResourceReader

Чтобы перечислить ресурсы в файле resources, вызовите GetEnumerator метод, который возвращает System.Collections.IDictionaryEnumerator объект. Метод вызывается IDictionaryEnumerator.MoveNext для перехода от одного ресурса к следующему. Метод возвращается false при перечислении всех ресурсов в файле ресурсов .resources.

Примечание.

ResourceReader Хотя класс реализует IEnumerable интерфейс и IEnumerable.GetEnumerator метод, ResourceReader.GetEnumerator метод не предоставляет реализациюIEnumerable.GetEnumerator. Вместо этого ResourceReader.GetEnumerator метод возвращает IDictionaryEnumerator объект интерфейса, предоставляющий доступ к паре имен и значений каждого ресурса.

Отдельные ресурсы в коллекции можно получить двумя способами:

  • Вы можете итерировать каждый ресурс в System.Collections.IDictionaryEnumerator коллекции и использовать System.Collections.IDictionaryEnumerator свойства для получения имени ресурса и значения. Мы рекомендуем этот метод, если все ресурсы имеют одинаковый тип или вы знаете тип данных каждого ресурса.

  • Имя каждого ресурса можно получить при итерации System.Collections.IDictionaryEnumerator коллекции и вызове GetResourceData метода для получения данных ресурса. Мы рекомендуем этот подход, если вы не знаете тип данных каждого ресурса или если предыдущий подход создает исключения.

Получение ресурсов с помощью свойств IDictionaryEnumerator

Первый метод перечисления ресурсов в файле .resources включает непосредственное получение пары имен и значений каждого ресурса. После вызова IDictionaryEnumerator.MoveNext метода для перемещения к каждому ресурсу в коллекции можно получить имя ресурса из IDictionaryEnumerator.Key свойства и данных ресурса из IDictionaryEnumerator.Value свойства.

В следующем примере показано, как получить имя и значение каждого ресурса в файле ресурсов с помощью IDictionaryEnumerator.Key свойств и IDictionaryEnumerator.Value свойств. Чтобы запустить пример, создайте следующий текстовый файл с именем ApplicationResources.txt для определения строковых ресурсов.

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

Затем можно преобразовать текстовый файл ресурсов в двоичный файл с именем ApplicationResources.resources с помощью следующей команды:

resgen ApplicationResources.txt

В следующем примере класс используется ResourceReader для перечисления каждого ресурса в автономном файле двоичных ресурсов и отображения имени ключа и соответствующего значения.

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)

Попытка получить данные ресурса из IDictionaryEnumerator.Value свойства может вызвать следующие исключения:

  • Если FormatException данные не заданы в ожидаемом формате.
  • Если FileNotFoundException сборка, содержащая тип, к которому относятся данные, не удается найти.
  • Если TypeLoadException тип, к которому относятся данные, не удается найти.

Как правило, эти исключения возникают, если файл .resources был изменен вручную, если сборка, в которой определен тип, либо не была включена в приложение или была непреднамеренно удалена, либо если сборка является старой версией, которая предопределяет тип. Если создается одно из этих исключений, можно получить ресурсы, перечислив каждый ресурс и вызвав GetResourceData метод, как показано в следующем разделе. Этот подход предоставляет некоторые сведения о типе данных, который IDictionaryEnumerator.Value свойство пыталось вернуть.

Получение ресурсов по имени с помощью GetResourceData

Второй подход к перечислению ресурсов в файле ресурсов также включает навигацию по ресурсам в файле путем вызова IDictionaryEnumerator.MoveNext метода. Для каждого ресурса извлекается имя ресурса из IDictionaryEnumerator.Key свойства, который затем передается GetResourceData(String, String, Byte[]) методу для получения данных ресурса. Возвращается в качестве массива байтов в аргументе resourceData .

Этот подход является более неловким, чем получение имени ресурса и значения из IDictionaryEnumerator.Key и IDictionaryEnumerator.Value свойств, так как возвращает фактические байты, которые образуют значение ресурса. Однако если попытка получить ресурс создает исключение, метод может помочь определить источник исключения, GetResourceData предоставив сведения о типе данных ресурса. Дополнительные сведения о строке, указывающей тип данных ресурса, см. в разделе GetResourceData.

В следующем примере показано, как использовать этот подход для извлечения ресурсов и обработки всех исключений, создаваемых. Он программно создает двоичный файл ресурсов .resources, содержащий четыре строки, одно логическое значение, одно целое число и одно растровое изображение. Чтобы выполнить пример, сделайте следующее:

  1. Скомпилируйте и выполните следующий исходный код, который создает файл .resources с именем 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();
            }
        }
    }
    

    Файл исходного кода называется CreateResources.cs. Его можно скомпилировать в C# с помощью следующей команды:

    csc CreateResources.cs /r:library.dll
    
  2. Скомпилируйте и запустите следующий код, чтобы перечислить ресурсы в файле 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();
        }
    }
    

    После изменения исходного кода (например, путем намеренного try создания FormatException в конце блока) можно запустить пример, чтобы узнать, как можно GetResourceData получить или повторно создать некоторые сведения о ресурсе.