應用場景:
設計一個任務調度系統,配置信息以XML行式保存在Tasks.config的配置文件裡,該配置裡不止一個任務。不同的任務,會有不同配置信息與設定。
解決方案1:使用XPath直接讀
優點:1. 直接;2. 靈活(配置可以千變萬化)
缺點:1. 不友好,要寫一堆的讀取XML數據的方法,每次有新的任務時都要重寫不同的XML片斷;2. 容易出錯,很有可能因為寫了一個錯誤的節點屬性名稱而得不到數據
解決方案2:使用對象序列化成XML文檔
缺點:1. 反序列化配置時必須有定義好的類型。
優點:1. 友好,XML裡的數據直接反序列化成對象的屬性;2. 不容易出錯,為什麼呢?你肯定要先定義好類型序列化後使用,你別告訴我你是手寫XML的;
現在的問題是設計一個方法,解決它的缺點。就算有不同的配置我也能給你反序列化出來。那麼抽出相同的部分,這部分不是我們關注的重點了。我們關注的是,如何重現不同的配置XML為實例。因為所有的對象都是繼承自object的,那麼,我們把擴展部分的類型就設定為object好了。經過測試發現,反序列化後的object是XmlNode[]數組。那我們要做的就是把這個XmlNode[]數組給轉換為文本,然後再客戶端使用的時候,將文本與定義好的類型進行反序列化。
代碼原型:
[Serializable,
XmlRoot(ElementName = "configuration")]
public class XmlConfig
{
/// <summary>
/// 擴展
/// </summary>
[XmlElement("extend")]
public object Extend { get; set; }
/// <summary>
/// 獲取已設定的擴展類型實例
/// </summary>
/// <typeparam name="T">擴展的類型</typeparam>
/// <returns>擴展類實例</returns>
public T GetExtend<T>() where T:class
{
return Serializer.XmlDeserializerFormText<T>(ExtendRawXml);
}
/// <summary>
/// Extend擴展的Xml片斷
/// </summary>
/// <returns></returns>
protected string ExtendRawXml
{
get
{
var nodes = Extend as XmlNode[];
if (nodes == null || nodes.Length == 0)
return "<extend />";
var w = new StringWriter();
XmlWriter writer = new XmlTextWriter(w);
writer.WriteStartElement("extend");
foreach (var node in nodes)
writer.WriteRaw(node.OuterXml);
writer.WriteEndElement();
writer.Close();
return w.ToString();
}
}
}
[Serializable,
XmlRoot("extend")]
public class MyExtend
{
public int Id { get; set; }
public string Name { get; set; }
}