Класс System.Resources.ResourceReader
В этой статье приводятся дополнительные замечания к справочной документации по этому API.
Важно!
Вызов методов этого класса для ненадежных данных представляет угрозу безопасности. Вызывайте методы класса только для надежных данных. Дополнительные сведения см. в разделе "Проверка всех входных данных".
Класс ResourceReader предоставляет стандартную реализацию IResourceReader интерфейса. ResourceReader Экземпляр представляет автономный файл ресурсов или файл .resources, внедренный в сборку. Он используется для перечисления ресурсов в файле ресурсов и получения пар "имя-значение". Он отличается от ResourceManager класса, который используется для извлечения указанных именованных ресурсов из файла РЕСУРСОВ, внедренного в сборку. Класс ResourceManager используется для получения ресурсов, имена которых известны заранее, в то время как ResourceReader класс полезен для получения ресурсов, число или точные имена которых не известны во время компиляции. Например, приложение может использовать файл ресурсов для хранения сведений о конфигурации, организованных в разделах и элементах в разделе, где количество разделов или элементов в разделе неизвестно заранее. Затем ресурсы могут называться универсально (напримерSection1
, , Section1Item1
Section1Item2
и т. д.) и извлекаться с помощью 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, содержащий четыре строки, одно логическое значение, одно целое число и одно растровое изображение. Чтобы выполнить пример, сделайте следующее:
Скомпилируйте и выполните следующий исходный код, который создает файл .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
Скомпилируйте и запустите следующий код, чтобы перечислить ресурсы в файле 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 получить или повторно создать некоторые сведения о ресурсе.