Przeglądaj wszystkie zasoby w pliku resx

125

Czy istnieje sposób na zapętlenie wszystkich zasobów w .resxpliku w C #?

np.
źródło
2
Czy możesz wyjaśnić, czy plik RESX jest wewnętrzny dla twojego projektu, czy też chcesz (lub musisz) odczytać oddzielny plik RESX lub odczytać RESX z innego zespołu?
Abel

Odpowiedzi:

243

Należy zawsze używać menedżera zasobów i nie czytać plików bezpośrednio, aby mieć pewność, że brana jest pod uwagę globalizacja.

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;
}
Oundless
źródło
12
Trochę zajęło mi ustalenie, że potrzebujesz tego wiersza do zadeklarowania MyResourceClass. ResourceManager MyResourceClass = new ResourceManager("Resources.ResourceFileName", System.Reflection.Assembly.Load("App_GlobalResources"));
JoeFletch
6
@JoeFletch: nie potrzebuje tej linii. Kod bezpośrednio wywołuje plik zasobów. Przykład: mam plik o nazwie PageList.resx, wtedy zadzwonię: ResourceSet resourceSet = PageList.ResourceManager.GetResourceSet (CultureInfo.CurrentUICulture, true, true);
Gabriel
@Gabriel, dzięki za aktualizację! Będę musiał wrócić do swojego kodu, aby to sprawdzić.
JoeFletch
3
Linia JoeFletcha faktycznie mi pomogła. Miałem resx znajdujący się w innym projekcie C #, więc jego linia pozwoliła mi wywołać ten zestaw dll i załadować zasoby w ten sposób. Ponadto, gdy próbowałem dołączyć PageList do mojego kodu, generował błąd dla PageList.ResourceManager .. mówiąc, że „PageList nie zawiera definicji dla ResourceManager”. I wreszcie string resourceKey = entry.Key wyrzucił błąd, zamiast tego użyłem „object resourceKey = entry.Key”
sksallaj
2
W zależności od tego, czy faktycznie masz zdefiniowane kultury w swoim zasobie, będziesz musiał przełączyć się do CultureInfo.InvariantCulture. Tutaj używałem zasobów w bibliotece, a nie aplikacji WinForms.
Israel Lopez
26

Blogowałem o tym na swoim blogu :) Krótka wersja to, aby znaleźć pełne nazwy zasobów (chyba, że ​​już je znasz):

var assembly = Assembly.GetExecutingAssembly();

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

Aby użyć ich wszystkich do czegoś:

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

Aby użyć zasobów w innych zestawach niż wykonujący, wystarczy uzyskać inny obiekt zestawu przy użyciu niektórych innych metod statycznych Assemblyklasy. Mam nadzieję, że to pomoże :)

Svish
źródło
Czy potrafisz wyliczyć zasoby, które nie znajdują się w folderze o nazwie „Zasób”? Chciałbym wyliczyć wszystkie obrazy zasobów znajdujące się w moim projekcie w folderze o nazwie „Obrazy”.
Simon Bosley
Na pewno nie dba o to, gdzie się znajduje? Sprawdź to?
Svish
1
Miałem pliki w folderze do inportowania plików sql i to działało idealnie. Dodałem konwersję ze strumienia do ciągu, dzięki czemu mogłem odczytać plik i nie miałem żadnych problemów.
ErocM
9

Użyj klasy 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());
}
rahul
źródło
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();

zobacz link: przykład firmy Microsoft

logicfalse
źródło
4
Zwróć uwagę, że ta klasa znajduje się w System.Windows.Formszestawie i nie jest automatycznie dodawana, jeśli używasz aplikacji MVC
Rob Scott
6

W chwili dodania pliku .RESX zasobu do projektu program Visual Studio utworzy plik Designer.cs o tej samej nazwie, tworząc dla Ciebie klasę ze wszystkimi elementami zasobu jako właściwościami statycznymi. Wszystkie nazwy zasobów można wyświetlić, wpisując kropkę w edytorze po wpisaniu nazwy pliku zasobów.

Alternatywnie możesz użyć odbicia, aby zapętlić te nazwy.

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
}

Ta metoda jest oczywiście używana tylko wtedy, gdy plik RESX znajduje się w zakresie bieżącego zestawu lub projektu. W przeciwnym razie użyj metody zapewnianej przez „puls”.

Zaletą tej metody jest to, że wywołujesz rzeczywiste właściwości, które zostały dla Ciebie dostarczone, biorąc pod uwagę dowolną lokalizację, jeśli chcesz. Jest to jednak raczej zbędne, ponieważ normalnie powinieneś używać bezpośredniej metody typu safe do wywoływania właściwości zasobów.

Abel
źródło
2
Po co używać odbicia, gdy dostępny jest zestaw zasobów?
Oundless
To jest to, co też bym się zastanawiał (patrz ostatni akapit). Chciałem tylko pokazać alternatywną metodę, ale co ważniejsze, chciałem pokazać, że klasa jest w pełni dostępna i nie musisz wykonywać żadnej magii ręcznie (pierwszy akapit).
Abel
1

Jeśli chcesz używać LINQ, użyj resourceSet.OfType<DictionaryEntry>(). Korzystanie z LINQ pozwala na przykład wybierać zasoby na podstawie ich indeksu (int) zamiast klucza (string):

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);
}
Ron Inbar
źródło
1

W przypadku pakietu System.Resources.ResourceManagerNuGet (wersja 4.3.0) ResourceSeti ResourceManager.GetResourceSetnie są dostępne.

Używając ResourceReader, jak sugeruje ten post: „ C # - Nie można pobrać ciągu z ResourceManager (z zestawu satelickiego)

Nadal można odczytać klucze / wartości pliku zasobów.

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;
   }
}
Jordy
źródło
0

Korzystanie z LINQ to SQL :

XDocument
        .Load(resxFileName)
        .Descendants()
        .Where(_ => _.Name == "data")
        .Select(_ => $"{ _.Attributes().First(a => a.Name == "name").Value} - {_.Value}");
Andriy Tolstoy
źródło
0

Prosta pętla odczytu używa tego kodu

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

foreach (DictionaryEntry dictionaryEntry in resx)
{
    Console.WriteLine("Key: " + dictionaryEntry.Key);
    Console.WriteLine("Val: " + dictionaryEntry.Value);
}
Azhe Kun
źródło