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

.NET的资源并不限于.resx文件(二)的更多相关文章

  1. .NET的资源并不限于.resx文件

    为了构建一个轻量级的资源管理框架以满足简单的本地化(Localization)的需求,我试图直接对现有的Resource编程模型进行扩展.虽然最终没能满足我们的需求,但是这两天也算对.NET如何进行资 ...

  2. resx文件在X64位编译,提示“未能加载文件或程序集”的问题?

    原文:resx文件在X64位编译,提示"未能加载文件或程序集"的问题? resx文件在X64位编译,提示"未能加载文件或程序集"的问题? 解答: 错误现象如下 ...

  3. [C++] 将 mp3 等音乐资源以资源形式嵌入 exe 文件中

    引用:http://www.easyx.cn/skills/View.aspx?id=6 本文讲解怎样将 mp3 等音乐资源以资源形式嵌入 exe 文件中,并通过 mciSendString 调用.嵌 ...

  4. .resources文件转.resx 文件

    最近在进行.net winform应用程序的反向工程,资源文件反向出来后都是.resources文件,工程编译和运行都没有问题,但.resources文件为二级制文件,无法在Visual Studio ...

  5. 将 mp3 等音乐资源以资源形式嵌入 exe 文件中

    引用:http://www.easyx.cn/skills/View.aspx?id=6 本文讲解怎样将 mp3 等音乐资源以资源形式嵌入 exe 文件中,并通过 mciSendString 调用.嵌 ...

  6. C#窗体的resx文件

    这些图片在项目文件中没找到,原来都存在了resx文件中. 属性界面的Image.BackgroundImage属性手动选择的图片会自动存储到resx文件中,之后这些图片源文件就可以删除了.resx中的 ...

  7. C#的Winform多语言实现(resx文件)

    1. 简体中文 2. 繁体中文 3. 英文 下面子丰介绍一下实现的过程: 1. 为每个窗口创建相应语言的resx文件.子丰以英文为例,右键->添加->新建项->资源文件,文件名为窗口 ...

  8. WPF 的另类资源方式 Resources.resx

      类似Winform的搞法,可以把资源放到Resources.resx中. 1.字符串 打开这个编辑器后,输入Name和Value就可以了. CS代码里面,很简单的调用: var title = W ...

  9. C#Winform中resx文件无效 找不到路径

    问题由来 笔者因为更改了添加的图片的路径,再把路径改成图片所在的路径还是报resx文件无效,未能找到路径 问题原因 其实这个问题是因为对对象的引用修改了,但是resx文件中的应用还是没有修改.因为re ...

随机推荐

  1. Pytorch随机种子

    最近在做比赛的时候,遇到了一个最好结果,但是之后无论怎样都复现不出来最好结果了.猜测是不是跟Pytorch中的随机种子有关. 训练过程 在训练过程中,若相同的数据数据集,相同的训练集.测试集划分方式, ...

  2. 北京VS上海:“活着为了工作”还是“工作为了生活”?

    Costco开业你去现场了吗?人口普查似的排队场面对于上海人来说已经不稀奇,毕竟当新鲜的商品或是业态来到中国时,上海常常是第一站.但当Costco的新闻不断发酵的同时,在互联网的角落里也有一群人提出了 ...

  3. Liferay7 Intellij IDEA 开发环境搭建

    一.安装Liferay插件 安装过程不在赘述,推荐两种安装方式: 通过Intellij插件市场安装 通过下载插件zip包安装 安装完成后,在项目板块中点鼠标右键,会出现Liferay菜单. 二.安装L ...

  4. C++走向远洋——38(用对象数组操作长方柱类)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:changfangzhu.cpp * 作者:常轩 * 微信公众号 ...

  5. 改进"尽最大努力交付"的服务

    改进"尽最大努力交付"的服务 网络层的作用就是负责在不同的网段尽力转发数据包,但是负责中专数据包的路由器并不关心数据包的内容和优先顺序.而是先到达的数据包先处理,后到达的数据包排队 ...

  6. Markdown 语法简要规则

    Markdown简介 Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用.看到这里请不要被「标记」.「语言」所迷惑,Markdown 的语法十分简 ...

  7. 三年前端,面试思考(头条蚂蚁美团offer)

    小鱼儿本人985本科,软件工程专业,前端.工作三年半,第一家创业公司,半年.第二家前端技术不错的公司,两年半.第三家,个人创业半年.可以看出,我是个很喜欢折腾的人,大学期间也做过很多项目,非常愿意参与 ...

  8. a标签嵌套href默认行为与子元素click事件存在影响

    2018-08-07 Question about work 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当<a>标签内部存在嵌套时, 父元素&l ...

  9. LVM简介及CentOS7 LVM操作实战

    LVM简介LVM是逻辑盘卷管理(LogicalVolumeManager)的简称,它是Linux环境下对磁盘分区进行管理的一种机制,LVM是建立在硬盘和 分区之上的一个逻辑层,来提高磁盘分区管理的灵活 ...

  10. 【,NetCore】WebApi使用统一时间格式

    1.在Startup中配置统一时间格式 services.AddMvc() .AddJsonOptions(options => { //配置时间序列化格式 options.Serializer ...