2016-08-01 4 views
2

Я пытаюсь создать файл ресурсов кодов сообщений. Я создал небольшой пример консоли, который терпит неудачу, когда я пытаюсь вызвать объект.Как создать и вызвать объекты класса из файла ресурсов, который я могу использовать во время выполнения?

Я основывал это на этом примере MSDN -Creating Resource Files, но я не знаю, что я пропустил, пытаясь упростить его.

В коде я запускаю его один раз для создания файла ресурсов и добавления этого файла в проект. Затем я перекомпиляю, чтобы запустить код отзыва.

using System; 
using System.Reflection; 
using System.Resources; 

namespace ResourceDemo 
{ 
    internal class Program 
    { 
    private static void Main(string[] args) 
    { 
     bool generateMode = false; 

     if (generateMode) { 
     // After running once with generate mode set to true, add the resulting 
     // "StatusItem.resource" that was created in the .\bin\x86\Debug folder 
     // to the project. 
     Generate(); 
     } 
     else { 
     // When run the next line generates an exception: 
     // An unhandled exception of type 'System.Resources.MissingManifestResourceException' occurred in mscorlib.dll 
     // 
     // Additional information: Could not find any resources appropriate for the specified culture 
     // or the neutral culture. Make sure "StatusItems.resources" was correctly embedded or linked 
     // into assembly "ResourceDemo" at compile time, or that all the satellite assemblies required 
     // are loadable and fully signed. 

     StatusItem statusItem = GetResource("2"); 
     Console.WriteLine("Id: {0} Message: {1}", statusItem.Id.ToString(), statusItem.Message); 
     Console.ReadKey(); 
     } 
    } 

    public static void Generate() 
    { 
     StatusItem[] statusItem = new StatusItem[4]; 

     // Instantiate an Status object items. 
     statusItem[0] = new StatusItem(2, "File not found"); 
     statusItem[1] = new StatusItem(3, "Path not found"); 
     statusItem[2] = new StatusItem(4, "Too many open files"); 
     statusItem[3] = new StatusItem(5, "File access denied"); 

     // Define a resource file named StatusItems.resx. 
     using (System.Resources.ResourceWriter rw = new ResourceWriter(@".\StatusItems.resources")) { 
     for (int i = 0; i < 4; i++) { 
      rw.AddResource(statusItem[i].Id.ToString(), statusItem[i]); 
     } 

     rw.Generate(); 
     } 
    } 

    public static StatusItem GetResource(string key) 
    { 
     Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); 
     System.Resources.ResourceManager rm = new System.Resources.ResourceManager("StatusItems", Assembly.Load("ResourceDemo")); 

     return (StatusItem)rm.GetObject(key); 
    } 

    [Serializable()] 
    public class StatusItem 
    { 
     public StatusItem(int id, string message) 
     { 
     Id = id; 
     Message = message; 
     } 

     public int Id { get; set; } 
     public string Message { get; set; } 
    } 
    } 
} 

ответ

1

Следующий код успешно создает не внедренный ресурс с использованием ResourceWriter и способен запоминать объекты данных с использованием словаря.

Кажется, что это нормально с IDE. Я попытался скомпилировать это в командной строке, но столкнулся с некоторыми другими проблемами, которые лучше оставить на отдельный вопрос. Я думаю, что это больше связано с коммандной линией, чем с кодом.

Я хотел опубликовать что-то, что конкретно отвечало на этот вопрос, хотя я, вероятно, возьму совет Питера Дунихо и вместо этого использую семейство ResxResourceWriter.

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Resources; 

namespace ResourceDemo 
{ 
    internal class Program 
    { 
    private const string nameSpace = "ResourceDemo"; 
    private const string resourceExtension = ".resources"; 
    private const string resourceFilename = "StatusItems"; 
    private static IDictionary<string, StatusItem> dictionary; 

    private static void Main(string[] args) 
    { 
     bool generateMode = false; 

     if (generateMode) { 
     // Only run when a new resource is added 
     Generate(); 
     } 
     else { 
     // Show the contents of the resource 
     EnumerateResource(); 

     // Make a dictionary so it is usable 
     BuildDictionary(); 

     Console.WriteLine("Look-up items 2, 4, 42 and 3 in dictionary"); 
     WriteStatusItemToConsole(GetResource("2")); 
     WriteStatusItemToConsole(GetResource("4")); 
     WriteStatusItemToConsole(GetResource("42")); 
     WriteStatusItemToConsole(GetResource("3")); 
     Console.ReadKey(); 
     } 
    } 

    /// <summary> 
    /// Build the working dictionary from the resource file 
    /// </summary> 
    public static void BuildDictionary() 
    { 
     Console.WriteLine("Building a look-up dictionary"); 
     StatusItem statusItem; 
     dictionary = new Dictionary<string, StatusItem>(); 
     ResourceReader res = new ResourceReader(@".\" + resourceFilename + resourceExtension); 

     IDictionaryEnumerator dict = res.GetEnumerator(); 
     while (dict.MoveNext()) { 
     statusItem = (StatusItem)dict.Value; 
     dictionary.Add(dict.Key.ToString(), statusItem); 
     } 
     res.Close(); 
     Console.WriteLine("{0} items written to dictionary.", dictionary.Count.ToString()); 
     Console.WriteLine(); 
    } 

    /// <summary> 
    /// List all the items inside the resource file. Assuming that the 
    /// </summary> 
    public static void EnumerateResource() 
    { 
     StatusItem statusItem; 
     Console.WriteLine("Resources in {0}", resourceFilename + resourceExtension); 
     ResourceReader res = new ResourceReader(@".\" + resourceFilename + resourceExtension); 
     IDictionaryEnumerator dict = res.GetEnumerator(); 
     Console.WriteLine("Dictionary Enumeration ready"); 
     while (dict.MoveNext()) { 
     statusItem = (StatusItem)dict.Value; 
     Console.WriteLine(" {0}: '{1}, {2}' (Type: {3})", dict.Key, statusItem.Id.ToString(), statusItem.Message, dict.Value.GetType().Name); 
     } 
     res.Close(); 
     Console.WriteLine(); 
    } 

    /// <summary> 
    /// Called to create the binary resource file. Needs to be called once. 
    /// </summary> 
    public static void Generate() 
    { 
     StatusItem[] statusItem = new StatusItem[4]; 

     // Instantiate some StatusItem objects. 
     statusItem[0] = new StatusItem(2, "File not found"); 
     statusItem[1] = new StatusItem(3, "Path not found"); 
     statusItem[2] = new StatusItem(4, "Too many open files"); 
     statusItem[3] = new StatusItem(5, "File access denied"); 

     // Define a resource file named StatusItems.resx. 
     using (System.Resources.ResourceWriter rw = new ResourceWriter(@".\" + resourceFilename + resourceExtension)) { 
     for (int i = 0; i < 4; i++) { 
      rw.AddResource(statusItem[i].Id.ToString(), statusItem[i]); 
     } 
     rw.Generate(); 
     } 
    } 

    /// <summary> 
    /// Look up StatusItem in dictionary with the given key 
    /// </summary> 
    /// <param name="key"></param> 
    /// <returns></returns> 
    public static StatusItem GetResource(string key) 
    { 
     StatusItem result = null; 
     if (dictionary != null) { 
     dictionary.TryGetValue(key, out result); 
     } 
     return result; 
    } 

    /// <summary> 
    /// Write the value of the given item to the console 
    /// </summary> 
    /// <param name="statusItem"></param> 
    public static void WriteStatusItemToConsole(StatusItem statusItem) 
    { 
     if (statusItem != null) { 
     Console.WriteLine(" Id: {0} Message: {1}", statusItem.Id, statusItem.Message); 
     } 
     else { 
     Console.WriteLine("Null Item"); 
     } 
    } 

    /// <summary> 
    /// This is our sample class 
    /// </summary> 
    [Serializable()] 
    public class StatusItem 
    { 
     public StatusItem(int id, string message) 
     { 
     Id = id; 
     Message = message; 
     } 

     public int Id { get; set; } 
     public string Message { get; set; } 
    } 
    } 
} 
1

& hellip; и добавить этот файл в проект

Как? Вы добавляете файл в среду IDE? Если это так, это не сработает ... что обрабатывает файл как обычные двоичные данные; это не интерпретируется как данные ресурсов. Вам нужно использовать /resource в командной строке или использовать al.exe для вставки файла .resource после факта.

Если вы хотите иметь возможность просто добавлять генерируемые ресурсы в проект, вы, вероятно, захотите использовать ResXResourceWriter вместо ResourceWriter. Затем вы получите файл .resx, который вы получите прямо в проект. Visual Studio скомпилирует файл .resx в файл .resources и автоматически внедряет его.

Это также имеет преимущество в создании файла для чтения человеком, и тот, который также можно открыть в среде IDE (хотя и с ограниченной функциональностью, в зависимости от типов, которые вы вставляете в него).

Предостережение:

  • ResXResourceWriter класса фактически определяются в System.Windows.Forms.dll, так что вам необходимо включить ссылку на эту сборку в проекте.
  • Типы, которые вы пишете в файл .resx, должны иметь возможность ссылаться во время компиляции, а это значит, что они не могут быть в той же сборке, которую вы компилируете. Вам нужно будет поместить их в отдельную DLL, на которую ссылается ваша программа.
  • Имя файла .resx ResourceManager будет полностью квалифицировано в контексте вашего проекта. Например, если вы добавите файл .resx в качестве файла верхнего уровня в своем проекте, вам нужно будет загрузить "ResourceDemo.StatusItems" вместо "StatusItems". Если вы добавите файл .resx «Как ссылка», он по умолчанию завершится в вашем проекте, содержащемся в папках, соответствующих файловой системе, например. "Bin \ Debug \ StatusItems.resx". В этом случае имя менеджера будет "ResourceDemo.bin.Debug.StatusItems".

Что касается этого последнего пункта, если вы когда-нибудь есть какие-либо вопросы об имени, вы можете использовать Assembly.GetManifestResourceNames(), чтобы проверить, что имена, которые были собраны в вашей программе.

+0

Я просто добавил существующий элемент к проекту. Я компилирую в ID, какую команду kine добавить параметр/resource? –

+0

@Rich: вам нужно будет скомпилировать ваш .cs-файл из командной строки с помощью csc.exe, предоставив переключатель '/ resource' для файла .resources, который вы хотите включить. Если вы хотите использовать формат файла .resource и по-прежнему включать его в качестве элемента Embedded Resource в проекте, вам нужно будет извлечь элемент как необработанные данные и класс 'ResourceReader' самостоятельно, чтобы действительно прочитать данные. Лично я бы пошел с опцией файла .resx, поскольку это обеспечивает лучшую интеграцию в обычные механизмы управления ресурсами. –

+0

Но если я использую семейство ResXResourceWriter, мне не нужно будет делать дополнительные шаги? –

Смежные вопросы