.NET的资源并不限于.resx文件,你可以采用任意存储形式[下篇]

简介:

在《上篇》中我们谈到ResourceManager在默认的情况下只能提供对内嵌于程序集的.resources资源文件的存取。为了实现对独立二进制.resources资源文件的支持,我们自定义了BinaryResoruceNManager。在本篇中我们还将创建两个自定义的ResourceManager,以实现对独立.resx资源文件自定义结构的XML资源文件的支持。(文中的例子从这里下载)

一、自定义ResXResourceManager实现对.Resx资源文件的支持
二、将资源定义在自定义结构的XML文件中
三、为XML资源存储形式定义ResourceReader和ResourceWriter
四、为XML资源存储形式定义ResourceSet
五、为XML资源存储形式定义ResourceManager
六、补充

 

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

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

   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文件对应的ReourceSet为ResXResourceSet,定义在System.Windows.Forms程序集中,所以在重写的InternalGetResourceSet中我们只需要返回这么一个ResXResourceSet即可。ResXResourceSet对应的ResourceReader为ResXResourceReader,而.resx文件可以通过ResXResourceWriter进行写入。

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

   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个重要的对象,它们分别是ResourceManager、ResourceSet、ResourceReader和ResourceWriter。要实现将自定义结构的XML作为资源文件,我们需要自定义这四个类型。

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

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

   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参数类型为string的AddResource方法。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

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

.NET的资源并不限于.resx文件,你可以采用任意存储形式[上篇]
.NET的资源并不限于.resx文件,你可以采用任意存储形式[下篇]


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
5月前
|
C++ Windows
.NET Framework安装不成功,下载`NET Framework 3.5`文件,Microsoft Visual C++
.NET Framework常见问题及解决方案汇总,涵盖缺失组件、安装失败、错误代码等,提供多种修复方法,包括全能王DLL修复工具、微软官方运行库及命令行安装等,适用于Windows系统,解决应用程序无法运行问题。
372 3
|
6月前
|
存储 缓存
.NET 6中Startup.cs文件注入本地缓存策略与服务生命周期管理实践:AddTransient, AddScoped, AddSingleton。
记住,选择正确的服务生命周期并妥善管理它们是至关重要的,因为它们直接影响你的应用程序的性能和行为。就像一个成功的建筑工地,工具箱如果整理得当,工具选择和使用得当,工地的整体效率将会大大提高。
236 0
|
12月前
|
Linux C# Windows
.NET使用MiniWord高效生成Word文件
.NET使用MiniWord高效生成Word文件
398 12
|
传感器 人工智能 供应链
.NET开发技术在数字化时代的创新作用,从高效的开发环境、强大的性能表现、丰富的库和框架资源等方面揭示了其关键优势。
本文深入探讨了.NET开发技术在数字化时代的创新作用,从高效的开发环境、强大的性能表现、丰富的库和框架资源等方面揭示了其关键优势。通过企业级应用、Web应用及移动应用的创新案例,展示了.NET在各领域的广泛应用和巨大潜力。展望未来,.NET将与新兴技术深度融合,拓展跨平台开发,推动云原生应用发展,持续创新。
163 4
Visual Studio 快速分析 .NET Dump 文件
【11月更文挑战第10天】.NET Dump 文件是在 .NET 应用程序崩溃或出现问题时生成的,记录了应用程序的状态,包括内存对象、线程栈和模块信息。通过分析这些文件,开发人员可以定位和解决内存泄漏、死锁等问题。在 Visual Studio 中,可以通过调试工具、内存分析工具和符号加载等功能来详细分析 Dump 文件。此外,还可以使用第三方工具如 WinDbg 进行更深入的分析。
685 1
|
数据库连接 开发者
.NET 内存管理两种有效的资源释放方式
【10月更文挑战第15天】在.NET中,有两种有效的资源释放方式:一是使用`using`语句,适用于实现`IDisposable`接口的对象,如文件流、数据库连接等,能确保资源及时释放,避免泄漏;二是手动调用`Dispose`方法并处理异常,提供更灵活的资源管理方式,适用于复杂场景。这两种方式都能有效管理资源,提高应用性能和稳定性。
321 2
|
算法 Java 数据库连接
.NET 内存管理两种有效的资源释放方式
【10月更文挑战第14天】在 .NET 中,`IDisposable` 接口提供了一种标准机制来释放非托管资源,如文件句柄、数据库连接等。此类资源需手动释放以避免泄漏。实现 `IDisposable` 的类可通过 `Dispose` 方法释放资源。使用 `using` 语句可确保资源自动释放。此外,.NET 的垃圾回收器会自动回收托管对象所占内存,提高程序效率。示例代码展示了如何使用 `MyFileHandler` 类处理文件操作并释放 `FileStream` 资源。
248 2
.NET 压缩/解压文件
【9月更文挑战第5天】在 .NET 中,可利用 `System.IO.Compression` 命名空间进行文件的压缩与解压。首先引入相关命名空间,然后通过 GZipStream 类实现具体的压缩或解压功能。下面提供了压缩与解压文件的方法示例及调用方式,便于用户快速上手操作。
181 6
|
C# Windows
一款基于.NET开发的简易高效的文件转换器
一款基于.NET开发的简易高效的文件转换器
127 0