Recorre todos los recursos en un archivo .resx

125

¿Hay alguna manera de recorrer todos los recursos en un .resxarchivo en C #?

notario público.
fuente
2
¿Puede explicar si el archivo RESX es interno a su proyecto o si desea (o necesita) leer un archivo RESX separado o leer RESX de otro ensamblado?
Abel

Respuestas:

243

Siempre debe usar el administrador de recursos y no leer los archivos directamente para garantizar que se tenga en cuenta la globalizació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;
}
Sin fin
fuente
12
Me tomó un poco darme cuenta de que necesita esta línea para declarar MyResourceClass. ResourceManager MyResourceClass = new ResourceManager("Resources.ResourceFileName", System.Reflection.Assembly.Load("App_GlobalResources"));
JoeFletch
66
@ JoeFletch: no necesita esta línea. El código llama al archivo de recursos directamente. Ejemplo: tengo un archivo llamado PageList.resx, luego llamaré: ResourceSet resourceSet = PageList.ResourceManager.GetResourceSet (CultureInfo.CurrentUICulture, true, true);
Gabriel
@ Gabriel, gracias por la actualización! Tendré que volver a mi código para ver esto.
JoeFletch
3
La línea de JoeFletch realmente me ayudó. Tenía un resx ubicado en otro proyecto de C #, por lo que su línea me permitió llamar a ese ensamblado de dll y cargar los recursos de esa manera. Además, cuando intenté incluir la PageList en mi código, arrojó un error para PageList.ResourceManager .. diciendo "PageList no contiene una definición para ResourceManager". Y finalmente, la cadena resourceKey = entry.Key arrojó un error, en su lugar usé "object resourceKey = entry.Key"
sksallaj
2
Dependiendo de si realmente tiene culturas definidas en su recurso, tendrá que cambiar a CultureInfo.InvariantCulture. Aquí estaba usando recursos en una biblioteca, no en una aplicación WinForms.
Israel López
26

Blogueado sobre esto en mi blog :) La versión corta es, para encontrar los nombres completos de los recursos (a menos que ya los conozca):

var assembly = Assembly.GetExecutingAssembly();

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

Para usarlos todos para algo:

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

Para usar recursos en ensamblajes distintos al ejecutante, solo obtendría un objeto de ensamblaje diferente utilizando algunos de los otros métodos estáticos de la Assemblyclase. Espero eso ayude :)

Svish
fuente
¿Puede enumerar recursos que no se encuentran en una carpeta llamada 'Recurso'? Me gustaría enumerar todas las imágenes de recursos ubicadas en mi proyecto en una carpeta llamada 'Imágenes'.
Simon Bosley
¿Estás seguro de que no le importa dónde se encuentra? ¿Pruébalo?
Svish
1
Tenía archivos en una carpeta para importar archivos sql y esto funcionó perfectamente. Agregué una conversión de una secuencia a una cadena para poder leer el archivo y no tuve problemas.
ErocM
9

Utilice la clase 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
fuente
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();

ver enlace: ejemplo de microsoft

Logicfalse
fuente
44
Tenga en cuenta que esta clase está en el System.Windows.Formsensamblado y no se agrega automáticamente si está utilizando una aplicación MVC
Rob Scott
6

En el momento en que agrega un archivo .RESX de recursos a su proyecto, Visual Studio creará un Designer.cs con el mismo nombre, creando una clase para usted con todos los elementos del recurso como propiedades estáticas. Puede ver todos los nombres del recurso cuando escribe el punto en el editor después de escribir el nombre del archivo de recursos.

Alternativamente, puede usar la reflexión para recorrer estos nombres.

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
}

Obviamente, este método solo se puede usar cuando el archivo RESX está dentro del alcance del ensamblaje o proyecto actual. De lo contrario, utilice el método proporcionado por "pulso".

La ventaja de este método es que llama a las propiedades reales que se le han proporcionado, teniendo en cuenta cualquier localización si lo desea. Sin embargo, es bastante redundante, ya que normalmente debe usar el método directo seguro de tipo para llamar a las propiedades de sus recursos.

Abel
fuente
2
¿Por qué usar la reflexión cuando hay un ResourceSet disponible?
Infinito el
Eso es lo que me preguntaría también (ver el último párrafo). Solo quería mostrar un método alternativo, pero lo que es más importante, quería mostrar que la clase es totalmente accesible y que no necesita hacer magia a mano (el primer párrafo).
Abel
1

Si desea usar LINQ, use resourceSet.OfType<DictionaryEntry>(). El uso de LINQ le permite, por ejemplo, seleccionar recursos en función de su índice (int) en lugar de la clave (cadena):

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
fuente
1

Con el paquete nuget System.Resources.ResourceManager(v4.3.0) ResourceSety ResourceManager.GetResourceSetno están disponibles.

Usando el ResourceReader, como sugiere esta publicación: " C # - No se puede obtener una cadena de ResourceManager (del ensamblaje satelital) "

Todavía es posible leer la clave / valores del archivo de recursos.

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
fuente
0

Usando LINQ to SQL :

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

El bucle de lectura simple usa este código

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
fuente