Lặp qua tất cả các tài nguyên trong tệp .resx


124

Có cách nào để lặp qua tất cả các tài nguyên trong một .resxtệp trong C # không?


2
Bạn có thể giải thích rõ liệu tệp RESX có nằm trong dự án của bạn không hoặc liệu bạn có muốn (hoặc cần) đọc một tệp RESX riêng hoặc đọc RESX từ một tổ hợp khác không?
Abel

Câu trả lời:


242

Bạn phải luôn luôn sử dụng trình quản lý tài nguyên và không đọc các tệp trực tiếp để đảm bảo tính toàn cầu hóa được tính đến.

using System.Collections;
using System.Globalization;
using System.Resources;

...

/* Reference to your resources class -- may be named differently in your case */
ResourceManager MyResourceClass =
    new ResourceManager(typeof(Resources));

ResourceSet resourceSet =
    MyResourceClass.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (DictionaryEntry entry in resourceSet)
{
    string resourceKey = entry.Key.ToString();
    object resource = entry.Value;
}

12
Tôi phải mất một chút để nhận ra rằng bạn cần dòng này để khai báo MyResourceClass. ResourceManager MyResourceClass = new ResourceManager("Resources.ResourceFileName", System.Reflection.Assembly.Load("App_GlobalResources"));
JoeFletch

6
@JoeFletch: nó không cần dòng này. Mã gọi tệp tài nguyên trực tiếp. Ví dụ: tôi có một tệp có tên là PageList.resx, sau đó tôi sẽ gọi: ResourceSet resourceSet = PageList.ResourceManager.GetResourceSet (CultureInfo.CiverseUICARM, true, true);
Gabriel

@Gabriel, cảm ơn đã cập nhật! Tôi sẽ phải quay lại mã của mình để kiểm tra điều này.
JoeFletch

3
Dòng của JoeFletch thực sự đã giúp tôi ra ngoài. Tôi đã có một resx nằm trong một dự án C # khác, vì vậy dòng của anh ấy cho phép tôi gọi lắp ráp dll đó và tải các tài nguyên theo cách đó. Ngoài ra, khi tôi cố gắng đưa PageList vào mã của mình, nó đã gây ra lỗi cho PageList.ResourceManager .. nói rằng "PageList không chứa định nghĩa cho ResourceManager". Và cuối cùng, chuỗi resourceKey = entry.Key đã đưa ra một lỗi, tôi đã sử dụng thay vì "object resourceKey = entry.Key"
sksallaj

2
Tùy thuộc vào việc bạn thực sự có các nền văn hóa được xác định trong tài nguyên của mình, bạn sẽ phải chuyển sang CultureInfo.InvariantCARM. Ở đây tôi đã sử dụng tài nguyên trong thư viện, không phải ứng dụng WinForms.
Israel Lopez

26

Đã viết về nó trên blog của tôi :) Phiên bản ngắn là, để tìm tên đầy đủ của các tài nguyên (trừ khi bạn đã biết chúng):

var assembly = Assembly.GetExecutingAssembly();

foreach (var resourceName in assembly.GetManifestResourceNames())
    System.Console.WriteLine(resourceName);

Để sử dụng tất cả chúng cho một cái gì đó:

foreach (var resourceName in assembly.GetManifestResourceNames())
{
    using(var stream = assembly.GetManifestResourceStream(resourceName))
    {
        // Do something with stream
    }
}

Để sử dụng tài nguyên trong các tập hợp khác ngoài tập hợp thực thi, bạn chỉ cần lấy một đối tượng lắp ráp khác bằng cách sử dụng một số phương thức tĩnh khác của Assemblylớp. Hy vọng nó giúp :)


Bạn có thể liệt kê các tài nguyên không nằm trong thư mục có tên 'Tài nguyên' không? Tôi muốn liệt kê tất cả các hình ảnh tài nguyên nằm trong dự án của tôi trong một thư mục có tên 'Hình ảnh'.
Simon Bosley

Khá chắc chắn rằng nó không quan tâm đến nơi nó nằm? Kiểm tra nó?
Svish

1
Tôi đã có các tệp trong một thư mục để nhập các tệp sql và điều này hoạt động hoàn hảo. Tôi đã thêm một chuyển đổi từ một luồng thành chuỗi để tôi có thể đọc tệp và không gặp vấn đề gì.
ErocM

9

Sử dụng lớp ResXResourceReader

ResXResourceReader rsxr = new ResXResourceReader("your resource file path");

// Iterate through the resources and display the contents to the console.
foreach (DictionaryEntry d in rsxr)
{
    Console.WriteLine(d.Key.ToString() + ":\t" + d.Value.ToString());
}

7
  // Create a ResXResourceReader for the file items.resx.
  ResXResourceReader rsxr = new ResXResourceReader("items.resx");

  // Create an IDictionaryEnumerator to iterate through the resources.
  IDictionaryEnumerator id = rsxr.GetEnumerator();       

  // Iterate through the resources and display the contents to the console.
  foreach (DictionaryEntry d in rsxr) 
  {
Console.WriteLine(d.Key.ToString() + ":\t" + d.Value.ToString());
  }

 //Close the reader.
 rsxr.Close();

xem liên kết: ví dụ microsoft


4
Lưu ý rằng lớp này nằm trong System.Windows.Formshội đồng và không được thêm tự động nếu bạn đang sử dụng ứng dụng MVC
Rob Scott

6

Ngay khi bạn thêm tệp .RESX tài nguyên vào dự án của mình, Visual Studio sẽ tạo một Designer.cs có cùng tên, tạo một lớp aa cho bạn với tất cả các mục của tài nguyên dưới dạng các thuộc tính tĩnh. Bạn có thể thấy tất cả các tên của tài nguyên khi bạn nhập dấu chấm vào trình chỉnh sửa sau khi bạn nhập tên của tệp tài nguyên.

Ngoài ra, bạn có thể sử dụng sự phản chiếu để lặp qua các tên này.

Type resourceType = Type.GetType("AssemblyName.Resource1");
PropertyInfo[] resourceProps = resourceType.GetProperties(
    BindingFlags.NonPublic | 
    BindingFlags.Static | 
    BindingFlags.GetProperty);

foreach (PropertyInfo info in resourceProps)
{
    string name = info.Name;
    object value = info.GetValue(null, null);  // object can be an image, a string whatever
    // do something with name and value
}

Phương pháp này rõ ràng chỉ có thể sử dụng được khi tệp RESX nằm trong phạm vi của tổ hợp hoặc dự án hiện tại. Mặt khác, sử dụng phương thức được cung cấp bởi "xung".

Ưu điểm của phương pháp này là bạn gọi các thuộc tính thực tế đã được cung cấp cho bạn, có tính đến bất kỳ nội địa hóa nào nếu bạn muốn. Tuy nhiên, nó khá dư thừa, vì thông thường bạn nên sử dụng loại phương thức trực tiếp an toàn để gọi các thuộc tính của tài nguyên của bạn.


2
Tại sao nên sử dụng sự phản chiếu khi có sẵn Bộ tài nguyên?
Vô dụng

Đó là điều tôi cũng thắc mắc (xem đoạn cuối). Chỉ muốn hiển thị một phương thức thay thế, nhưng quan trọng hơn, muốn cho thấy rằng lớp được tạo hoàn toàn có thể truy cập và bạn không cần phải thực hiện bất kỳ phép thuật nào bằng tay (đoạn đầu tiên).
Abel


1

Nếu bạn muốn sử dụng LINQ, hãy sử dụng resourceSet.OfType<DictionaryEntry>(). Ví dụ, sử dụng LINQ cho phép bạn chọn tài nguyên dựa trên chỉ mục (int) của chúng thay vì khóa (chuỗi):

ResourceSet resourceSet = Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (var entry in resourceSet.OfType<DictionaryEntry>().Select((item, i) => new { Index = i, Key = item.Key, Value = item.Value }))
{
    Console.WriteLine(@"[{0}] {1}", entry.Index, entry.Key);
}

1

Với gói System.Resources.ResourceManagernuget (v4.3.0), ResourceSetResourceManager.GetResourceSetkhông có sẵn.

Sử dụng ResourceReader, như bài đăng này đề xuất: " C # - Không thể nhận chuỗi từ ResourceManager (từ lắp ráp vệ tinh) "

Vẫn có thể đọc khóa / giá trị của tệp tài nguyên.

System.Reflection.Assembly resourceAssembly = System.Reflection.Assembly.Load(new System.Reflection.AssemblyName("YourAssemblyName"));
String[] manifests = resourceAssembly.GetManifestResourceNames(); 
using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
{
   System.Collections.IDictionaryEnumerator dict = reader.GetEnumerator();
   while (dict.MoveNext())
   {
      String key = dict.Key as String;
      String value = dict.Value as String;
   }
}

0

Sử dụng LINQ để SQL :

XDocument
        .Load(resxFileName)
        .Descendants()
        .Where(_ => _.Name == "data")
        .Select(_ => $"{ _.Attributes().First(a => a.Name == "name").Value} - {_.Value}");

0

Vòng lặp đọc đơn giản sử dụng mã này

var resx = ResourcesName.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, false, false);

foreach (DictionaryEntry dictionaryEntry in resx)
{
    Console.WriteLine("Key: " + dictionaryEntry.Key);
    Console.WriteLine("Val: " + dictionaryEntry.Value);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.