System.Resources.ResourceReader 類別

本文提供此 API 參考文件的補充備註。

重要

使用不信任的資料呼叫此類別的方法,會造成安全性上的風險。 呼叫此類別的方法時,請一律使用信任的資料。 如需詳細資訊,請參閱 驗證所有輸入

類別 ResourceReader 提供介面的標準實作 IResourceReaderResourceReader實例代表獨立 .resources 檔案或內嵌在元件中的 .resources 檔案。 它用來列舉 .resources 檔案中的資源,並擷取其名稱/值組。 它與 ResourceManager 類別不同,用來從內嵌在元件中的 .resources 檔案擷取指定的具名資源。 類別 ResourceManager 是用來擷取事先知道其名稱的資源,而 類別 ResourceReader 可用於擷取在編譯時期未知數目或精確名稱的資源。 例如,應用程式可能會使用資源檔來儲存組態資訊,該資訊會組織成區段中的區段和專案,其中區段中的區段或項目數目事先未知。 然後,資源可以泛型命名(例如 Section1Section1Item1Section1Item2等),並使用 ResourceReader 對象來擷取。

重要

此型別代表 IDisposable 介面。 當您完成使用型別時,您應該直接或間接處置它。 若要直接處置型別,請呼叫其 try/catch 區塊中的 Dispose 方法。 若要間接處置它,請使用語言建構函式,例如 using (在 C# 中) 或 Using (在 Visual Basic 中)。 如需詳細資訊,請參閱介面檔中的<使用實作 IDisposable 的物件>一節 IDisposable

具現化 ResourceReader 物件

.resources 檔案是二進位檔,由 Resgen.exe (資源文件產生器)文本檔或 XML .resx 檔案編譯。 ResourceReader物件可以代表獨立 .resources 檔案或已內嵌在元件中的 .resources 檔案。

若要具現化 ResourceReader 從獨立 .resources 檔案讀取的物件,請使用 ResourceReader 類別建構函式搭配輸入數據流或包含 .resources 檔名的字串。 下列範例說明這兩種方法。 第一個 ResourceReader 具現化 對象,這個物件代表使用其檔名命名的 Resources1.resources .resources 檔案。 第二個 ResourceReader 會使用從檔案建立的數據流,具現化 物件,代表名為 Resources2.resources 的 .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)

若要建立 ResourceReader 代表內嵌 .resources 檔案的物件,請從內嵌 .resources 檔案的元件具現化 Assembly 物件。 其 Assembly.GetManifestResourceStream 方法會 Stream 傳回可傳遞至建構函式的物件 ResourceReader(Stream) 。 下列範例會具現化 ResourceReader 代表內嵌 .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)

列舉 ResourceReader 對象的資源

若要列舉 .resources 檔案中的資源,您可以呼叫 GetEnumerator 方法,以傳 System.Collections.IDictionaryEnumerator 回 物件。 您可以呼叫 IDictionaryEnumerator.MoveNext 方法,將資源從一個資源移至下一個資源。 方法會在 false 列舉 .resources 檔案中的所有資源時傳回。

注意

ResourceReader雖然 類別會實作 IEnumerable 介面和 IEnumerable.GetEnumerator 方法,ResourceReader.GetEnumerator但方法不會提供 實作IEnumerable.GetEnumerator。 相反地 ResourceReader.GetEnumerator ,方法會 IDictionaryEnumerator 傳回介面物件,以提供每個資源名稱/值組的存取權。

您可以透過兩種方式擷取集合中的個別資源:

使用 IDictionaryEnumerator 屬性擷取資源

列舉 .resources 檔案中資源的第一個方法牽涉到直接擷取每個資源的名稱/值組。 呼叫 IDictionaryEnumerator.MoveNext 方法以移至集合中的每個資源之後,您可以從 屬性擷取資源名稱 IDictionaryEnumerator.Key ,並從屬性擷取資源數據 IDictionaryEnumerator.Value

下列範例示範如何使用 和 IDictionaryEnumerator.Value 屬性,擷取 .resources 檔案IDictionaryEnumerator.Key中每個資源的名稱和值。 若要執行此範例,請建立名為 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 類別來列舉獨立二進位 .resources 檔案中的每個資源,並顯示其索引鍵名稱和對應的值。

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 屬性擷取資源數據可能會擲回下列例外狀況:

一般而言,如果已手動修改 .resources 檔案、定義型別的元件尚未包含在應用程式或意外刪除,或元件是較舊的版本,則會擲回這些例外狀況。 如果擲回其中一個例外狀況,您可以列舉每個資源並呼叫 GetResourceData 方法來擷取資源,如下一節所示。 此方法提供屬性嘗試傳回之數據類型 IDictionaryEnumerator.Value 的一些資訊。

使用 GetResourceData 依名稱擷取資源

列舉 .resources 檔案中資源的第二種方法也牽涉到藉由呼叫 IDictionaryEnumerator.MoveNext 方法來巡覽檔案中的資源。 針對每個資源,您會從 IDictionaryEnumerator.Key 屬性擷取資源的名稱,然後傳遞給 GetResourceData(String, String, Byte[]) 方法以擷取資源的數據。 這會以 自變數中的 resourceData 位元組陣列的形式傳回。

這種方法比從 IDictionaryEnumerator.KeyIDictionaryEnumerator.Value 屬性擷取資源名稱和值更尷尬,因為它會傳回形成資源值的實際位元組。 不過,如果嘗試擷取資源擲回例外狀況, GetResourceData 方法可藉由提供資源數據類型的相關信息來協助識別例外狀況的來源。 如需指出資源資料類型之字串的詳細資訊,請參閱 GetResourceData

下列範例說明如何使用此方法來擷取資源,以及處理擲回的任何例外狀況。 它會以程序設計方式建立二進位 .resources 檔案,其中包含四個字串、一個布爾值、一個整數和一個位圖。 若要執行此範例,請執行下列動作:

  1. 編譯並執行下列原始程式碼,這會建立名為 ContactResources.resources 的 .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讓您擷取或重新建立某些資源資訊。