讀他人源碼,摘錄一些好代碼
public class Configuration
{
private XmlDocument xmlDoc;
private string xmlPath;
private Hashtable basicValues;
private Hashtable arrayValues;
/// <summary>
/// 獲取基本配置中的字符串類型鍵值。
/// </summary>
/// <param name="key">配置字段的索引。</param>
/// <returns>找到返回字符串,否則返回 null。</returns>
public string GetString(string key)
{
key = key.ToLower();
return basicValues.ContainsKey(key) ?
_SafeGetString((string)basicValues[key]) : null;
}
/// <summary>
/// 讀取基本配置中的字符串類型鍵值。
/// </summary>
/// <param name="key">配置字段的索引。</param>
/// <param name="defaultValue">找不到指定字段時返回的默認值。</param>
/// <returns>找到返回字符串,否則返回 defaultValue。</returns>
public string ReadString(string key, string defaultValue)
{
key = key.ToLower();
return basicValues.ContainsKey(key) ?
_SafeGetString((string)basicValues[key]) : defaultValue;
}
/// <summary>
/// 設置基本配置中的字符串類型鍵值。
/// </summary>
/// <param name="key">配置字段的索引。</param>
/// <param name="value">配置字段的值。</param>
public void WriteString(string key, string value)
{
key = key.ToLower();
basicValues[key] = value;
}
/// <summary>
/// 讀取基本配置中的 Int32 類型鍵值。
/// </summary>
/// <param name="key">配置字段的索引。</param>
/// <param name="defaultValue">找不到指定字段或字段值不合法時返回的默認值。</param>
/// <returns>找到並返回合法的 Int32 值,否則返回 defaultValue。</returns>
public int ReadInt32(string key, int defaultValue)
{
int ret = 0;
if (!int.TryParse(ReadString(key, defaultValue.ToString()), out ret))
return defaultValue;
else
return ret;
}
/// <summary>
/// 設置基本配置中的 Int32 類型鍵值。
/// </summary>
/// <param name="key">配置字段的索引。</param>
/// <param name="value">配置字段的值。</param>
public void WriteInt32(string key, int value)
{
WriteString(key, value.ToString());
}
/// <summary>
/// 讀取基本配置中的 Boolean 類型鍵值。
/// </summary>
/// <param name="key">配置字段的索引。</param>
/// <param name="defaultValue">找不到指定字段或字段值不合法時返回的默認值。</param>
/// <returns>找到並返回合法的 Boolean 值,否則返回 defaultValue。</returns>
public bool ReadBoolean(string key, bool defaultValue)
{
bool ret = false;
if (!bool.TryParse(ReadString(key, defaultValue.ToString()), out ret))
return defaultValue;
else
return ret;
}
/// <summary>
/// 設置基本配置中的 Boolean 類型鍵值。
/// </summary>
/// <param name="key">配置字段的索引。</param>
/// <param name="value">配置字段的值。</param>
public void WriteBoolean(string key, bool value)
{
WriteString(key, value.ToString());
}
/// <summary>
/// 移除基本配置中的鍵值。
/// </summary>
/// <param name="key">字段的索引。</param>
public void DeleteValue(string key)
{
key = key.ToLower();
if (basicValues.ContainsKey(key))
basicValues.Remove(key);
}
/// <summary>
/// 暴露整個配置文件的文檔結構。<br />
/// 雖然不是良好的範例,但是我覺得這樣在此處比較合理。
/// </summary>
public XmlDocument XmlDocument
{
get
{
return xmlDoc;
}
}
/// <summary>
/// 取得命名數組配置對象。
/// </summary>
/// <param name="name">數組名稱。</param>
/// <returns>找到命名對象則返回該對象,否則返回 null。</returns>
public string[] GetArray(string name)
{
name = name.ToLower();
return (string[])arrayValues[name];
}
/// <summary>
/// 以安全訪問的方式取得數組配置對象。
/// </summary>
/// <param name="name">數組名稱。</param>
/// <returns>找到命名對象則返回該對象,否則返回空的字符串數組實例。</returns>
public string[] SafeGetArray(string name)
{
string[] arr = GetArray(name);
return arr != null ? arr : new string[0];
}
/// <summary>
/// 設置命名數組配置對象(整體賦值)。
/// </summary>
/// <param name="name">數組名稱。</param>
/// <param name="array">要設置成的數組。</param>
public void SetArray(string name, string[] array)
{
name = name.ToLower();
if (array == null)
throw new ArgumentNullException("array");
arrayValues[name] = array;
}
/// <summary>
/// 取得命名數組某項值。
/// </summary>
/// <param name="name">數組名稱。</param>
/// <param name="index">項在數組中的索引。</param>
/// <returns>如果沒有找到數組返回 null。如果索引越界則引發。</returns>
/// <exception cref="IndexOutOfRangeException"></exception>
public string GetArrayItem(string name, int index)
{
string[] arr = GetArray(name);
if (arr != null)
{
if (index >= 0 && index < arr.Length)
return arr[index];
else
throw new IndexOutOfRangeException();
}
else
return null;
}
/// <summary>
/// 設置命名數組某項值。
/// </summary>
/// <param name="name">數組名稱。</param>
/// <param name="index">項在數組中的索引。</param>
/// <param name="value">要設置成的值。</param>
/// <exception cref="IndexOutOfRangeException"></exception>
/// <exception cref="InvalidOperationException">當數組不存在時拋出。</exception>
public void SetArrayItem(string name, int index, string value)
{
string[] arr = GetArray(name);
if (arr != null)
{
if (index >= 0 && index < arr.Length)
arr[index] = value;
else
throw new IndexOutOfRangeException();
}
else
{
throw new InvalidOperationException(string.Format("數組 {0} 不存在。", name));
}
}
/// <summary>
/// 移除數組配置中的數組。
/// </summary>
/// <param name="name">數組的名稱。</param>
public void DeleteArray(string name)
{
name = name.ToLower();
if (arrayValues.ContainsKey(name))
arrayValues.Remove(name);
}
/// <summary>
/// 新建一個 Configuration 類的實例。
/// </summary>
/// <param name="configPath">配置文件路徑</param>
public Configuration(string configPath)
{
if (configPath == null)
{
throw new ArgumentNullException("configPath");
}
xmlPath = configPath;
// 讀入配置
try
{
loadConfig();
}
catch
{
xmlDoc = new XmlDocument();
basicValues = new Hashtable();
arrayValues = new Hashtable();
XmlNode xmlNd = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
xmlDoc.AppendChild(xmlNd);
xmlNd = xmlDoc.CreateNode(XmlNodeType.Element, "revolution", "");
xmlDoc.AppendChild(xmlNd);
}
}
/// <summary>
/// 保存配置文件。
/// </summary>
/// <exception cref="AiryAi.Revolution.Core.Exceptions.ConfigurationException"></exception>
public void SaveConfig()
{
saveConfig();
}
/// <summary>
/// 重新載入配置文件。
/// </summary>
/// <exception cref="AiryAi.Revolution.Core.Exceptions.ConfigurationException"></exception>
public void ReloadConfig()
{
// 備份原有數據
Hashtable _basicValues = basicValues;
Hashtable _arrayValues = arrayValues;
XmlDocument _xmlDoc = xmlDoc;
// 嘗試載入數據
try
{
loadConfig();
}
catch
{
basicValues = _basicValues;
xmlDoc = _xmlDoc;
arrayValues = _arrayValues;
throw;
}
// 銷燬備份
_arrayValues = null;
_basicValues = null;
_xmlDoc = null;
}
private string _SafeGetString(string str)
{
return str != null ? str : String.Empty;
}
private void saveConfig()
{
try
{
// 重建 XML 文檔樹
XmlNode xmlRt = xmlDoc.SelectSingleNode("revolution");
if (xmlRt == null)
{
xmlRt = xmlDoc.CreateNode(XmlNodeType.Element, "revolution", "");
xmlDoc.AppendChild(xmlRt);
}
// 重建 Revolution/Config
XmlNode xmlNd = xmlDoc.SelectSingleNode("revolution/config");
if (xmlNd == null)
{
xmlNd = xmlDoc.CreateNode(XmlNodeType.Element, "config", "");
xmlRt.AppendChild(xmlNd);
}
else
{
XmlNode ndd = xmlDoc.CreateNode(XmlNodeType.Element, "config", "");
xmlRt.ReplaceChild(ndd, xmlNd);
xmlNd = ndd;
}
//xmlNd.RemoveAll();
// 重建 Revolution/Arrays
XmlNode xmlArr = xmlDoc.SelectSingleNode("revolution/arrays");
if (xmlArr == null)
{
xmlArr = xmlDoc.CreateNode(XmlNodeType.Element, "arrays", "");
xmlRt.AppendChild(xmlArr);
}
else
{
XmlNode ndd = xmlDoc.CreateNode(XmlNodeType.Element, "arrays", "");
xmlRt.ReplaceChild(ndd, xmlArr);
xmlArr = ndd;
}
// 開始添加 add 節點
foreach (string key in basicValues.Keys)
{
XmlNode nd = xmlDoc.CreateNode(XmlNodeType.Element, "add", "");
nd.Attributes.Append(
xmlDoc.CreateAttribute("key")
);
nd.Attributes.Append(
xmlDoc.CreateAttribute("value")
);
nd.Attributes["key"].Value = key;
nd.Attributes["value"].Value = _SafeGetString((string)basicValues[key]);
xmlNd.AppendChild(nd);
}
// 開始添加 array 節點
foreach (string key in arrayValues.Keys)
{
XmlNode nd = xmlDoc.CreateNode(XmlNodeType.Element, "array", "");
string[] arr = (string[])arrayValues[key];
nd.Attributes.Append(
xmlDoc.CreateAttribute("name")
);
nd.Attributes["name"].Value = key;
// Create the items
foreach (string value in arr)
{
XmlNode item = xmlDoc.CreateNode(XmlNodeType.Element, "item", "");
item.AppendChild(
xmlDoc.CreateTextNode(_SafeGetString(value))
);
nd.AppendChild(item);
}
// Replace or append
xmlArr.AppendChild(nd);
}
// 保存 XML 文檔
xmlDoc.PreserveWhitespace = false;
xmlDoc.Save(xmlPath);
}
catch (IOException ioex)
{
Debugger.LogException(ioex);
throw new Exceptions.ConfigurationException("無法保存配置文件,原因可能是文件被佔用,或者當前用戶沒有該權限。", ioex);
}
catch (Exception ex)
{
Debugger.LogException(ex);
throw new Exceptions.ConfigurationException("因爲未知錯誤,無法保存配置文件。", ex);
}
}
private void loadConfig()
{
xmlDoc = new XmlDocument();
try
{
// 打開 XML
xmlDoc.Load(xmlPath);
// 讀取基本配置字段
basicValues = new Hashtable();
this.arrayValues = new Hashtable();
XmlNodeList addValues = xmlDoc.SelectNodes("revolution/config/add");
if (addValues != null && addValues.Count > 0)
{
foreach (XmlNode nd in addValues)
{
string key, value;
key = nd.Attributes["key"] != null ? nd.Attributes["key"].Value : String.Empty;
value = nd.Attributes["value"] != null ? nd.Attributes["value"].Value : String.Empty;
if (!string.IsNullOrEmpty(key))
{
value = value != null ? value : String.Empty;
basicValues[key.ToLower()] = value;
}
}
}
// 讀取 Array 配置
XmlNodeList arrayValues = xmlDoc.SelectNodes("revolution/arrays/array");
if (arrayValues != null && arrayValues.Count > 0)
{
foreach (XmlNode arr in arrayValues)
{
if (arr.Attributes["name"] == null
|| string.IsNullOrEmpty(arr.Attributes["name"].Value))
continue;
List<string> strList = new List<string>();
// Pass through items
foreach (XmlNode item in arr.ChildNodes)
{
if (item.Name == "item"
&& item.ChildNodes.Count > 0)
{
if (item.ChildNodes[0].NodeType == XmlNodeType.Text
|| item.ChildNodes[0].NodeType == XmlNodeType.CDATA)
strList.Add(item.ChildNodes[0].Value);
}
}
// add to list
this.arrayValues[arr.Attributes["name"].Value.ToLower()] = strList.ToArray();
}
}
}
catch (IOException ioex)
{
Debugger.LogException(ioex);
throw new Exceptions.ConfigurationException("無法讀取配置文件,原因可能是文件被佔用,或者當前用戶沒有該權限。", ioex);
}
catch (Exception ex)
{
Debugger.LogException(ex);
throw new Exceptions.ConfigurationException("因爲未知錯誤,無法讀取配置文件。", ex);
}
}
}
爲了在任何時間能夠輕鬆訪問配置文件,進一步可以這樣處理:
/// <summary>
/// 快速訪問特定程序內容的靜態類。
/// </summary>
public static class App
{
// 靜態構造
static App()
{
config = new Configuration(Path.Combine(Environment.CurrentDirectory, "config.xml"));
}
// 快速靜態全局變量
private static Configuration config;
/// <summary>
/// 讀取配置文件對象。
/// </summary>
public static Configuration Config
{
get
{
return config;
}
}
/// <summary>
/// 提供重新定向配置文件的接口。
/// </summary>
/// <param name="configPath">。配置文件路徑</param>
public static void ReInit(string configPath)
{
config = new Configuration(configPath);
}
}
這樣就可以使用 App.Config 來訪問我們的配置文件了。