리소스(resources)를 통합 관리 해보자.

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (8/19/2008 10:43:15 AM) Viewing : 5887

리소스는 참 관리 하기 어려운 존재이다.

기본 적으로 VS 에서는 하나의 어셈블리마다 각각의 리소스를 사용할 수 있으며 파일명을 가지고 culture를 구분하여 동적으로 런타임시에 해당 리소스를 바인딩 하는 형식이 되겠다.

그러나 하나의 솔루션에 속하는 프로젝트가 많아 지다 보면 각각의 프로젝트에 속한 리소스를 관리하기가 여간...만만치않다.

나도 역시 이 문제 때문에 고민을 하다가 약간은 조잡할지 모르나 나름구성을 해보았다.

먼저 사용할 리소스의 형태는 확장자가 resX인 XML 형태와, 확장자가 resources 인 바이너리형태 , 2가지가 있다.
리소스를 작성하기 위해서는 IDE에 내장되어 있는 리소스 편집기를 이용하여도 상관 없으나 따로 Resourcer.NET 이라는 무료 도구를 이용하도록 하겠다.
사용법은 간단하니..pass 하도록 하겠다.

샘플프로젝트구조

샘플 프로젝트의 구조는 다음과 같다.
먼저 리소스를 관리할 BIT.TM.Resources 라는 프로젝트가 있다. 이 프로젝트에는 Proxies 라는 폴더와 Resources 라는 폴더가 있는데 관심있게 살펴 봐야 한다.
이 리소스를 사용할 프로젝트는 Sample 이라는 프로젝트이다. 
일반적으로 리소스는 그것을 사용할 프로젝트에 같이 있어야 하나, 분리를 시켜 독자적으로 관리 하게끔 하였다.
Proxies 라는 폴더와 Resources 라는 폴더에 있는 파일의 네이밍규칙을 살펴 보자.

이 리소스를 사용할 프로젝트의 네임스페이스를 사용하고 있다.
즉  문자열 리소스의 경우 Proxies 클래스의 네이밍룰은 {네임스페이스}.StringProxy.cs 가 되며, 
리소스의 경우 {네임스페이스}.String.{CultureCode(생략가능)}.resources 가 된다.

서두에 언급하였지만 리소스의 형식은 resX가 되었던 resources 가 되었던 상관은 없다.

자.. 이제 코드를 살펴 보자..
먼저 ResourceType 열거형을 살펴 보자.

    ///

    /// 리소스의 타입 열거형 Ver 1.0

    ///

    ///

    /// 2007.12.11 - Prototype - 이방은(http://www.bangsil.net)

    ///

    public enum ResourceType

    {

        ///

        /// 아이콘 타입입니다.

        ///

        Icon,

        ///

        /// 문자열 타입입니다.

        ///

        String,

        ///

        /// 이미지 타입입니다.

        ///

        Image

    }

리소스의 형식을 정의하는 열거형이다.
이제 리소스 파일을 읽어 관리하는 ResourceManager 를 살펴 보자.

   34 public CustomResourceManager(ResourceType resourceType, Type type)

   35 {

   36     bool hasResource = false;

   37     Assembly asm = Assembly.GetCallingAssembly();

   38     string resourceName = this.GetType().Namespace + ".Resources." + type.Namespace + "." + resourceType.ToString();

   39     foreach (string reName in asm.GetManifestResourceNames())

   40     {

   41         if (reName.Substring(0,reName.LastIndexOf('.')) == resourceName)

   42         {

   43             hasResource = true;

   44             break;

   45         }

   46     }

   47     if (!hasResource)

   48     {

   49         throw new MissingManifestResourceException("해당 타입의 리소스를 찾을 수 없습니다.");

   50     }

   51     else

   52     {

   53         rm = new ResourceManager(resourceName, asm);

   54     }

   55 }

생성자를 보게 되면 앞서 정의한 ResourceType열거형과 Type 개체를 받는걸 볼수 있다.
38행을 보게 되면 매개변수로 받은 type 변수로 호출할 어셈블리의 네임스페이스를 알아내고 이를 이용해 리소스 이름을 생성하는 것을 볼 수 있다.

그외 메서드로는

  104 ///

  105 /// 해당 키를 가지고 있는 문자열 타입의 리소스를 반환합니다.

  106 ///

  107 /// 리소스를 호출 할 키입니다.

  108 /// 반환되는 리소스입니다.

  109 internal string GetString(string key)

  110 {

  111     if (key.Length == 0)

  112     {

  113         return null;

  114     }

  115     try

  116     {

  117         return rm.GetString(key);

  118     }

  119     catch

  120     {

  121         return null;

  122     }

  123 }

과 같은 리소스의 값을 반환하는 메서드가 존재한다.

이제 Proxies 개체를 만들어 보도록 하겠다.

    7 namespace Sample

    8 {

    9     ///

   10     /// 문자열 리소스 Proxy 클래스 Ver 1.0

   11     ///

   12     /// 2007.12.11 - Prototype - 이방은(http://www.bangsil.net)

   13     public class StringProxy

   14     {

   15         private static CustomResourceManager rm;

   16

   17         ///

   18         /// 클래스의 정적 생성자입니다.

   19         ///

   20         static StringProxy()

   21         {

   22             rm = new CustomResourceManager(ResourceType.String, typeof(StringProxy));

   23         }

   24

   25         public static string TestString

   26         {

   27             get { return rm.GetString("TestString"); }

   28         }

   29     }

   30 }

주의 할 것은 이 프락시 클래스의 네임스페이스이다.
네임스페이스를 보게 되면 이 클래스가 존재하는 어셈블리의 이름(BIT.TM.Resources)이 아니고 이 클래스를 사용할 어셈블리의 네임스페이스가 등록된다.
그리고 정적 생성자에서 조금 전에 설명했던 CustomResourceManager 개체를 만들고 호출할 리소스의 키를 Property로 제공하기만 하면 된다.

이미지 프락시의 경우는 아래와 같다.

    8 namespace Sample

    9 {

   10     public class ImageProxy

   11     {

   12         private static CustomResourceManager rm;

   13

   14         ///

   15         /// 클래스의 정적 생성자입니다.

   16         ///

   17         static ImageProxy()

   18         {

   19             rm = new CustomResourceManager(ResourceType.Image, typeof(ImageProxy));

   20         }

   21

   22         public static Image TestImage

   23         {

   24             get { return rm.GetImage("TestImage"); }

   25         }

   26     }

   27 }

자 이제 리소스는 모두 정의 되어 있으니 이것을 사용하는 코드만 남았다.

Sample 프로젝트는 비즈니스계층으로 이 리소스를 사용하는 곳이 되겠다.

    8     public class Sample

    9     {

   10         public static string GetString()

   11         {

   12             return StringProxy.TestString;

   13         }

   14

   15         public static Image GetImage()

   16         {

   17             return ImageProxy.TestImage;

   18         }

   19     }

간단하게 위 처럼 정의해 보았다.
이제 이 개체를 Culture를 변경시켜 보여주도록 하기위에 폼단에서 코드를 손을 본다.

   19 private void Form1_Load(object sender, EventArgs e)

   20 {

   21     this.label4.Text = Sample.Sample.GetString();

   22     this.pictureBox1.Image = Sample.Sample.GetImage();

   23

   24     Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");

   25     this.label3.Text = Sample.Sample.GetString();

   26 }

20행과 21행은 한글버전이므로 
Sample.String.resources와 Sample.Image.resources 파을일 읽게 될 것이며
24행의 Culture변환으로 인해
25행의 경우에는 영문버전이 되므로
Sample.String.en.resources를 읽게 된다. 
그 결과는 아래와 같다.

실행결과

나름대로 짱구를 굴려 보았지만..현재까지는 이정도가 한계인듯 하다.
리소스 관리에 대해 더 좋은 의견이 있다면 
언제든 환영........


마지막 업데이트 : (9/15/2010 2:41:56 PM)

TAG : 리소스 resource 



첨부 파일 보기 (1)
Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기