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

作者: Artech  來源: 博客園  發布時間: 2011-01-07 10:35  閱讀: 886 次  推薦: 0   原文鏈接   [收藏]  

  在《上篇》中我們談到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的定義僅僅為你提供了一種實現自定義資源存儲形式的解決方案,按照一樣的思路,你可以采用其他的資源存儲形式,比較有價值的應該是將資源內容定義在數據庫表中。在分布式架構中,你甚至可以通過遠程調用服務的方式來獲取資源,不過在這種情況下,你應該考慮進行相應的緩存機制提升性能。

0
0
 
標簽:.NET
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()