zoukankan      html  css  js  c++  java
  • .NET的资源并不限于.resx文件(二)

    ResourceManager在默认的情况下只能提供对内嵌于程序集的.resources资源文件的存取。
    为了实现对独立二进制.resources资源文件的支持,我们自定义了BinaryResoruceNManager
    在本篇中将创建两个自定义的ResourceManager,以实现对独立.resx资源文件和自定义结构的XML资源文件的支持。

    一、自定义ResXResourceManager实现对.Resx资源文件的支持

    较之.resources资源文件这种二进制文件,以XML形式定义的.Resx资源文件是一个纯文本文件,我们可以对其进行自由地修改,所以有时候我们直接将独立的.resx文件作为资源存储形式更利于资源内容的维护。我们创建自定义的BinaryResourceManager实现了对独立.resources资源文件的支持,我们仅仅需要采用相似的方式定义一个ResXResourceManager。由于.NET已经提供了支持.Resx资源文件的ResourceSetResourceReaderResourceWriter,所以ResXResourceManagerBinaryResourceManager一样简单,下面是其全部定义。

       1: public class ResXResourceManager : FileResourceManager
       2: {
       3:     public ResXResourceManager(string directory, string baseName)
       4:         : base(directory, baseName, ".resx")
       5:     {}
       6:  
       7:     protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
       8:     {
       9:         return new ResXResourceSet(this.GetResourceFileName(culture));
      10:     }
      11: }
    

    .resx文件对应的ReourceSetResXResourceSet,定义在System.Windows.Forms程序集中,所以在重写的InternalGetResourceSet中我们只需要返回这么一个ResXResourceSet即可。ResXResourceSet对应的ResourceReaderResXResourceReader,而.resx文件可以通过ResXResourceWriter进行写入。

    既然我们的ResXResourceManager已经创建好了,我们就可以将它应用到我们的演示程序中。演示代码如下所示,三个辅助方法PrepareFilesAddResourceDisplayResource的实现可以参考《上篇》,后面列出的是与之前的演示完全一样的输出结果。

       1: PrepareFiles("GreetingMessages", "resx");
       2:  
       3: AddResource(() => new ResXResourceWriter("GreetingMessages.resx"), new CultureInfo("en-US"));
       4: AddResource(() => new ResXResourceWriter("GreetingMessages.en-US.resx"), new CultureInfo("en-US"));
       5: AddResource(() => new ResXResourceWriter("GreetingMessages.zh-CN.resx"), new CultureInfo("zh-CN"));
       6:  
       7: DisplayResource(new ResXResourceManager("", "GreetingMessages"));
    

    输出结果

       1: English (United States)
       2:         Merry Christmas!
       3:         Happy Chinese New Year!
       4:  
       5: Chinese (Simplified, PRC)
       6:         圣诞快乐!
       7:         新年快乐!
       8:  
       9: Japanese (Japan)
      10:         Merry Christmas!
      11:         Happy Chinese New Year!
    

    二、将资源定义在自定义结构的XML文件中

    .Resx资源文件本质上就是一XML文件,既然.Resx文件可以作为资源文件,我们肯定可以将资源定义在我们自定义的XML文件中。由于仅仅是作为演示,我尽可能简化这个XML的结构,并且仅仅提供纯文本资源内容的支持。我们自定义XML资源文件具有如下的结构:

       1: <?xml version="1.0" encoding="utf-8"?>
       2: <resources>
       3:   <add name="Greeting4Chris" value="Merry Christmas!" />
       4:   <add name="Greeting4NewYear" value="Happy Chinese New Year!" />
       5: </resources>
    

    .NET的资源体系包含4个重要的对象,它们分别是ResourceManagerResourceSetResourceReaderResourceWriter。要实现将自定义结构的XML作为资源文件,我们需要自定义这四个类型。

    三、为XML资源存储形式定义ResourceReader和ResourceWriter

    我定义了如下一个XmlResourceReader作为读取XML资源文件的ResourceWriterXmlResourceReader实现接口IResourceReader,在构造函数中将资源内容从XML文件中读取出来保存在一个XmlDocument对象中。在GetEnumerator方法中将该XmlDocument得内容转换成一个Hashtable,并返回该HashtableEnumerator

       1: public class XmlResourceReader: IResourceReader
       2: {
       3:     public XmlDocument Document { get; private set; }
       4:     public XmlResourceReader(string fileName)
       5:     {
       6:         this.Document = new XmlDocument();
       7:         this.Document.Load(fileName);
       8:     }
       9:     public XmlResourceReader(Stream stream)
      10:     {
      11:         this.Document = new XmlDocument();
      12:         this.Document.Load(stream);
      13:     }
      14:     public IDictionaryEnumerator GetEnumerator()
      15:     {
      16:         Dictionary<string, string> set = new Dictionary<string, string>();
      17:         foreach (XmlNode item in this.Document.GetElementsByTagName("add"))
      18:         {
      19:             set.Add(item.Attributes["name"].Value, item.Attributes["value"].Value);
      20:         }
      21:         return set.GetEnumerator();
      22:     }
      23:     IEnumerator IEnumerable.GetEnumerator()
      24:     {
      25:         return GetEnumerator();
      26:     }
      27:     public void Dispose(){}
      28:     public void Close(){}
      29: }
    

    将资源内容写入XML文件的实现定义在如下一个名为XmlResourceWriter的文件中,它实现接口IResourceWriter。上面说过我们的XML仅仅提供对于纯文本内容的支持,在这里我们仅仅实现了value参数类型为stringAddResource方法。XmlResourceWriter的逻辑很简单,仅仅涉及到对于XmlDocument节点的添加和保存,所以在这里无需再多作介绍了。

       1: public class XmlResourceWriter: IResourceWriter
       2: {
       3:     public XmlDocument Document { get; private set; }
       4:     private string fileName;
       5:     private XmlElement root;
       6:  
       7:     public XmlResourceWriter(string fileName)
       8:     {           
       9:         this.fileName = fileName;
      10:         this.Document = new XmlDocument();
      11:         this.Document.AppendChild(this.Document.CreateXmlDeclaration("1.0", "utf-8",null));
      12:         this.root = this.Document.CreateElement("resources");
      13:         this.Document.AppendChild(this.root);
      14:     }
      15:  
      16:     public void AddResource(string name, byte[] value)
      17:     {
      18:         throw new NotImplementedException();
      19:     }
      20:  
      21:     public void AddResource(string name, object value)
      22:     {
      23:         throw new NotImplementedException();
      24:     }
      25:  
      26:     public void AddResource(string name, string value)
      27:     {
      28:         var node = this.Document.CreateElement("add");
      29:         node.SetAttribute("name", name);
      30:         node.SetAttribute("value", value);
      31:         this.root.AppendChild(node);
      32:     }
      33:  
      34:     public void Generate()
      35:     {
      36:         using (XmlWriter writer = new XmlTextWriter(this.fileName, Encoding.UTF8))
      37:         {
      38:             this.Document.WriteTo(writer);
      39:         }
      40:     }
      41:     public void Dispose(){}
      42:     public void Close() { }
      43: }
    

    四、为XML资源存储形式定义ResourceSet

    ResourceReaderResourceWriter已经创建完毕,现在我们来创建自定义的ResourceSet:XmlResorceSet。我们定义的XmlResourceReader在构造函数中被实例化,在ReadResource方法执行过程中,它将被用于完成资源内容的读取操作,读取的结果最终用于初始化该XmlResuorceSet对象。

       1: public class XmlResourceSet : ResourceSet
       2: {
       3:     public XmlResourceSet(Stream stream)
       4:     {
       5:         this.Reader = new XmlResourceReader(stream);
       6:         this.Table = new Hashtable();
       7:         this.ReadResources();
       8:     }
       9:     public XmlResourceSet(string fileName)
      10:     {
      11:         base.Reader = new XmlResourceReader(fileName);
      12:         base.Table = new Hashtable();
      13:         this.ReadResources();
      14:     }
      15:     public override Type GetDefaultReader()
      16:     {
      17:         return typeof(XmlResourceReader);
      18:     }
      19:     public override Type GetDefaultWriter()
      20:     {
      21:         return typeof(XmlResourceWriter);
      22:     }
      23: }
    

    五、为XML资源存储形式定义ResourceManager

    最后一部自然是创建我们自定义的ResourceManager:XmlResourceManager。和之前创建的BinaryResourceManager、ResXResourceManager一样,我们只需要重写InternalGetResourceSet方法,返回相应的ResourceSet对象即可,在这里返回的自然是上面创建的XmlResourceSet

       1: public class XmlResourceManager: FileResourceManager
       2: {
       3:     public XmlResourceManager(string directory, string baseName)
       4:         : base(directory, baseName, ".xml")
       5:     {}
       6:  
       7:     protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
       8:     {
       9:         return new XmlResourceSet(this.GetResourceFileName(culture));
      10:     }
      11: }
    

    XmlResourceManager放进我们的演示程序,你依然可以得到一样的结果

       1: PrepareFiles("GreetingMessages", "xml");
       2:  
       3: AddResource(() => new XmlResourceWriter("GreetingMessages.xml"), new CultureInfo("en-US"));
       4: AddResource(() => new XmlResourceWriter("GreetingMessages.en-US.xml"), new CultureInfo("en-US"));
       5: AddResource(() => new XmlResourceWriter("GreetingMessages.zh-CN.xml"), new CultureInfo("zh-CN"));
       6:  
       7: DisplayResource(new XmlResourceManager("", "GreetingMessages"));
    

    执行结果

       1: English (United States)
       2:         Merry Christmas!
       3:         Happy Chinese New Year!
       4:  
       5: Chinese (Simplified, PRC)
       6:         圣诞快乐!
       7:         新年快乐!
       8:  
       9: Japanese (Japan)
      10:         Merry Christmas!
      11:         Happy Chinese New Year!
    

    六、补充

    XmlResourceManager的定义仅仅为你提供了一种实现自定义资源存储形式的解决方案,按照一样的思路,你可以采用其他的资源存储形式,比较有价值的应该是将资源内容定义在数据库表中。在分布式架构中,你甚至可以通过远程调用服务的方式来获取资源,不过在这种情况下,你应该考虑进行相应的缓存机制提升性能。

  • 相关阅读:
    Android 主题theme说明 摘记
    Android开发 去掉标题栏方法 摘记
    安卓项目五子棋代码详解(二)
    关于 ake sure class name exists, is public, and has an empty constructor that is public
    百度地图3.0实现图文并茂的覆盖物
    android onSaveInstanceState()及其配对方法。
    关于集成科大讯飞语音识别的 一个问题总结
    android 关于 webview 控制其它view的显示 以及更改view数据失败的问题总结
    C# 解析 json Newtonsoft果然强大,代码写的真好
    c#数据类型 与sql的对应关系 以及 取值范围
  • 原文地址:https://www.cnblogs.com/wxlevel/p/7833231.html
Copyright © 2011-2022 走看看