• 一起谈.NET技术,.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一样简单,下面是其全部定义。

    public class ResXResourceManager : FileResourceManager
    {
    public ResXResourceManager(string directory, string baseName)
    :
    base(directory, baseName, ".resx")
    {}

    protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
    {
    return new ResXResourceSet(this.GetResourceFileName(culture));
    }
    }

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

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

    PrepareFiles("GreetingMessages", "resx");

    AddResource(()
    => new ResXResourceWriter("GreetingMessages.resx"), new CultureInfo("en-US"));
    AddResource(()
    => new ResXResourceWriter("GreetingMessages.en-US.resx"), new CultureInfo("en-US"));
    AddResource(()
    => new ResXResourceWriter("GreetingMessages.zh-CN.resx"), new CultureInfo("zh-CN"));

    DisplayResource(
    new ResXResourceManager("", "GreetingMessages"));

      输出结果:

    English (United States)
    Merry Christmas
    !
    Happy Chinese New Year
    !

    Chinese (Simplified, PRC)
    圣诞快乐
    !
    新年快乐
    !

    Japanese (Japan)
    Merry Christmas
    !
    Happy Chinese New Year
    !

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

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

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

      《上篇》中讲到,.NET的资源体系包含4个重要的对象,它们分别是ResourceManager、ResourceSet、ResourceReader和ResourceWriter。要实现将自定义结构的XML作为资源文件,我们需要自定义这四个类型。

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

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

    public class XmlResourceReader: IResourceReader
    {
    public XmlDocument Document { get; private set; }
    public XmlResourceReader(string fileName)
    {
    this.Document = new XmlDocument();
    this.Document.Load(fileName);
    }
    public XmlResourceReader(Stream stream)
    {
    this.Document = new XmlDocument();
    this.Document.Load(stream);
    }
    public IDictionaryEnumerator GetEnumerator()
    {
    Dictionary
    <string, string> set = new Dictionary<string, string>();
    foreach (XmlNode item in this.Document.GetElementsByTagName("add"))
    {
    set.Add(item.Attributes["name"].Value, item.Attributes["value"].Value);
    }
    return set.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
    return GetEnumerator();
    }
    public void Dispose(){}
    public void Close(){}
    }

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

    ublic class XmlResourceWriter: IResourceWriter
    {
    public XmlDocument Document { get; private set; }
    private string fileName;
    private XmlElement root;

    public XmlResourceWriter(string fileName)
    {
    this.fileName = fileName;
    this.Document = new XmlDocument();
    this.Document.AppendChild(this.Document.CreateXmlDeclaration("1.0", "utf-8",null));
    this.root = this.Document.CreateElement("resources");
    this.Document.AppendChild(this.root);
    }

    public void AddResource(string name, byte[] value)
    {
    throw new NotImplementedException();
    }

    public void AddResource(string name, object value)
    {
    throw new NotImplementedException();
    }

    public void AddResource(string name, string value)
    {
    var node
    = this.Document.CreateElement("add");
    node.SetAttribute(
    "name", name);
    node.SetAttribute(
    "value", value);
    this.root.AppendChild(node);
    }

    public void Generate()
    {
    using (XmlWriter writer = new XmlTextWriter(this.fileName, Encoding.UTF8))
    {
    this.Document.WriteTo(writer);
    }
    }
    public void Dispose(){}
    public void Close() { }
    }

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

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

    public class XmlResourceSet : ResourceSet
    {
    public XmlResourceSet(Stream stream)
    {
    this.Reader = new XmlResourceReader(stream);
    this.Table = new Hashtable();
    this.ReadResources();
    }
    public XmlResourceSet(string fileName)
    {
    base.Reader = new XmlResourceReader(fileName);
    base.Table = new Hashtable();
    this.ReadResources();
    }
    public override Type GetDefaultReader()
    {
    return typeof(XmlResourceReader);
    }
    public override Type GetDefaultWriter()
    {
    return typeof(XmlResourceWriter);
    }
    }

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

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

    public class XmlResourceManager: FileResourceManager
    {
    public XmlResourceManager(string directory, string baseName)
    :
    base(directory, baseName, ".xml")
    {}

    protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
    {
    return new XmlResourceSet(this.GetResourceFileName(culture));
    }
    }

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

    PrepareFiles("GreetingMessages", "xml");

    AddResource(()
    => new XmlResourceWriter("GreetingMessages.xml"), new CultureInfo("en-US"));
    AddResource(()
    => new XmlResourceWriter("GreetingMessages.en-US.xml"), new CultureInfo("en-US"));
    AddResource(()
    => new XmlResourceWriter("GreetingMessages.zh-CN.xml"), new CultureInfo("zh-CN"));

    DisplayResource(
    new XmlResourceManager("", "GreetingMessages"));

      执行结果:

    English (United States)
    Merry Christmas
    !
    Happy Chinese New Year
    !

    Chinese (Simplified, PRC)
    圣诞快乐
    !
    新年快乐
    !

    Japanese (Japan)
    Merry Christmas
    !
    Happy Chinese New Year
    !

      六、补充

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

  • 相关阅读:
    【Hadoop】:HDFS调用Java API进行操作
    aws安装
    神奇的 SQL 之性能优化 → 让 SQL 飞起来
    Hunting and Analyzing High CPU Usage in .NET Applications(实践篇)(转发)
    使用 SOS 对 Linux 中运行的 .NET Core 进行问题诊断(实践篇)(转发)
    good resouces ——开发视频网站推荐(channel9)
    ASP.NET Core 3.1 微软官方教程
    perfview——(教学)
    Dump collection and analysis utility (dotnet-dump)
    Trace for performance analysis utility (dotnet-trace)
  • 原文地址:https://www.cnblogs.com/waw/p/2163072.html
Copyright © 2020-2023  润新知