2016-08-01 1 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에서 제대로 작동하는 것 같습니다. 커맨드 라인에서 이것을 컴파일하려고 시도했지만 다른 문제에 더 잘 대처했습니다. 필자는 코드보다 컴플리트 라인 컴파일과 관련이 있다고 생각한다.

피터 듀 니호 (Peter Duniho)의 조언을 받아 들여 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 파일을 임베드해야합니다.

생성 된 리소스 출력을 프로젝트에 간단하게 추가하려면 ResourceWriter 대신 ResXResourceWriter을 사용하는 것이 좋습니다. 그런 다음 .resx 파일을 받게됩니다.이 파일은 수 있습니다. 프로젝트에 직접 추가하십시오. Visual Studio는 .resx 파일을 .resources 파일로 컴파일하고 올바르게 자동으로 포함시킵니다.

사람이 읽을 수있는 파일을 만들 수있는 장점과 IDE에서 열 수있는 파일 (제한된 기능 임에도 불구하고 넣은 파일 유형에 따라 다름)이 있습니다.

주의 사항은 : 프로젝트에서 해당 어셈블리에 대한 참조를 포함해야합니다, 그래서

  • ResXResourceWriter 클래스는 실제로 System.Windows.Forms.dll에 정의되어 있습니다.
  • .resx 파일에 쓰는 유형은 컴파일 할 때 참조 할 수 있어야합니다. 즉, 컴파일 할 때 동일한 어셈블리에있을 수 없습니다. 프로그램에 의해 참조되는 별도의 DLL에 이들을 넣어야합니다.
  • .resx 파일의 ResourceManager 이름은 프로젝트의 컨텍스트에서 정규화됩니다. 예를 들어 .resx 파일을 프로젝트의 최상위 파일로 추가한다고 가정하면 "StatusItems" 대신 "ResourceDemo.StatusItems"을로드해야합니다. .resx 파일을 "링크"로 추가하면 기본적으로 파일 시스템에 해당하는 폴더에 포함 된 프로젝트에서 종료됩니다. "bin \ Debug \ StatusItems.resx"를 입력하십시오. 이 경우 관리자 이름은 "ResourceDemo.bin.Debug.StatusItems"이됩니다.

이름에 대해 궁금한 점이 있으면 Assembly.GetManifestResourceNames()을 사용하여 프로그램에 컴파일 된 이름이 무엇인지 검사 할 수 있습니다.

+0

단순히 기존 항목을 프로젝트에 추가했습니다. 나는 ID로 컴파일하고 있는데, 어떤 커맨드 kine을/resource 옵션에 추가합니까? –

+0

@ 리치 : 포함시키려는 .resources 파일에 대해'/ resource' 스위치를 제공하여 csc.exe를 사용하여 명령 줄에서 .cs 파일을 컴파일해야합니다. .resource 파일 형식을 사용하고 프로젝트에 Embedded Resource 항목으로 포함하려는 경우 항목을 원시 데이터로 검색하고 'ResourceReader' 클래스를 직접 읽어 데이터를 읽어야합니다. 개인적으로, .resx 파일 옵션을 사용하면 일반적인 리소스 관리 메커니즘과 가장 잘 통합됩니다. –

+0

그러나 ResXResourceWriter 제품군을 사용하면 추가 단계를 수행하지 않아도됩니까? –

관련 문제