一、前言
可擴展標記語言 (XML) 是具有結(jié)構(gòu)性的標記語言,可以用來標記數(shù)據(jù)、定義數(shù)據(jù)類型,是一種允許用戶對自己的標記語言進行定義的源語言。XML是用來存儲數(shù)據(jù)的,重在數(shù)據(jù)本身。本文中的代碼是幾個月前整理的,最近幾個月的時間很少寫隨筆,除了工作以外,主要還是忙于整理自己的框架。這篇隨筆主要是針對于XML的特性Attribute與實體之間的匹配與轉(zhuǎn)換,其中的內(nèi)容包括反射、XML以及LinqToXml,代碼的內(nèi)容也是想到什么就寫什么,純屬練習下手感,僅供參考。下一篇隨筆將以另外的形式來轉(zhuǎn)換Xml為對象實體,當然,也是以反射為主,和本隨筆中的思路差不多,主要是XML的格式和解決方案不同而已。對于如何將對象轉(zhuǎn)換成Xml的話,主要還是看情況,僅僅轉(zhuǎn)換簡單的對象的話,直接反射就可以生成。對于復雜的對象的話,可以采用dynamic,樹結(jié)構(gòu)和遞歸算法的方案來定制XML。
二、類圖設(shè)計
該處的主要思路為:通過反射將與類名(類特性名稱或者類名)的節(jié)點匹配,然后匹配屬性(屬性特性名稱或者屬性名稱)值。反之,則遍歷實體對象的屬性,設(shè)置相應(yīng)的XML。本來還想細化一下匹配與轉(zhuǎn)換操作的,但是該類的EA文件不知道放在哪里了,只有設(shè)計的截圖還在,XO。相關(guān)類圖設(shè)計如下:
PropertyAttribute主要設(shè)置屬性的特性名稱,用于轉(zhuǎn)換過程設(shè)置屬性的別名,同時匹配過程中匹配XML的特性與屬性的名稱。
ClassAttribute主要設(shè)置類的特性名稱,用于轉(zhuǎn)換過程設(shè)置類的別名,同時匹配過程中匹配XML的節(jié)點與類的名稱。
StringExtension主要是字符串的擴展方法。
FuncDictionary主要轉(zhuǎn)換字符串為特定類型的值。
XmlAttributeUtility主要轉(zhuǎn)換實體對象為XML以及匹配XML為實體對象,其中還包括一些其他基本操作。
三、具體實現(xiàn)
先看下FuncDictionary,該類主要通過異步委托將字符串轉(zhuǎn)換成相應(yīng)的簡單類型,所有實現(xiàn)圍繞該類進行相關(guān)操作。FuncDictionary基本涵蓋了C#中的所有簡單類型,可以將字符串轉(zhuǎn)換成這些簡單類型。
主要方法為:public object DynamicInvoke(Type type, string arg),通過傳入的類型和字符串值,可以轉(zhuǎn)換成相應(yīng)的Object值。屬性Dictionary中涵蓋了所有簡單類型轉(zhuǎn)換的委托操作。代碼如下:
1 public class FuncDictionary
2 {
3 public static IDictionary<Type, Delegate> Dictionary
4 {
5 get;
6 private set;
7 }
8
9 static FuncDictionary()
10 {
11 if (FuncDictionary.Dictionary == null)
12 {
13 FuncDictionary.Dictionary = CreateDictionary();
14 }
15 }
16
17 public object DynamicInvoke(Type type, string arg)
18 {
19 if (type == null)
20 {
21 return null;
22 }
23
24 if (FuncDictionary.Dictionary == null)
25 {
26 FuncDictionary.Dictionary = CreateDictionary();
27 }
28
29 if (!FuncDictionary.Dictionary.ContainsKey(type))
30 {
31 return null;
32 }
33
34 Delegate action = FuncDictionary.Dictionary[type];
35
36 return action.DynamicInvoke(new object[] { arg });
37 }
38
39 public static IDictionary<Type, Delegate> CreateDictionary()
40 {
41 var dictionary = new Dictionary<Type, Delegate>();
42
43 dictionary.Add(typeof(string), new Func<string, string>(p => p));
44 dictionary.Add(typeof(decimal), new Func<string, decimal>(p => p.AsDecimal()));
45 dictionary.Add(typeof(DateTime), new Func<string, DateTime>(p => p.AsDateTime()));
46 dictionary.Add(typeof(float), new Func<string, float>(p => p.AsFloat()));
47 dictionary.Add(typeof(double), new Func<string, double>(p => p.AsDouble()));
48 dictionary.Add(typeof(int), new Func<string, int>(p => p.AsInt()));
49 dictionary.Add(typeof(byte), new Func<string, byte>(p => p.AsByte()));
50 dictionary.Add(typeof(sbyte), new Func<string, sbyte>(p => p.AsSbyte()));
51 dictionary.Add(typeof(short), new Func<string, short>(p => p.AsShort()));
52 dictionary.Add(typeof(ushort), new Func<string, ushort>(p => p.AsUshort()));
53 dictionary.Add(typeof(uint), new Func<string, uint>(p => p.AsUint()));
54 dictionary.Add(typeof(long), new Func<string, long>(p => p.AsLong()));
55 dictionary.Add(typeof(ulong), new Func<string, ulong>(p => p.AsUlong()));
56 dictionary.Add(typeof(char), new Func<string, char>(p => p.AsChar()));
57 dictionary.Add(typeof(bool), new Func<string, bool>(p => p.AsBool()));
58 dictionary.Add(typeof(Color), new Func<string, Color>(p => p.AsColor()));
59
60 return dictionary;
61 }
62 }
再看下XmlAttributeUtility類,該類主要包括轉(zhuǎn)換和匹配操作。匹配主要為兩種方案(主要邏輯為以下代碼的72-183行):
1、通過XmlReader順序讀取來設(shè)置實體的值,主要方法為public static IList<T> Parse<T>(XmlReader reader) where T : new():
2、通過遍歷XmlNodeList中的節(jié)點,依次遍歷節(jié)點中的XmlAttribute設(shè)置實體的屬性的值,主要方法為:public static IList<T> Parse<T>(XmlNodeList nodeList) where T : new()
XmlAttributeUtility的轉(zhuǎn)換操作相對來說比較簡單,采用反射+LinqToXml轉(zhuǎn)換操作就很簡單了,主要實現(xiàn)方法為public static XElement Convert<T>(T entity) where T : new(),其他方法都是以該方法作為基礎(chǔ)來進行操作。為什么用LinqToXml?主要原因是LinqToXml比Xml更方便,很多細節(jié)方面不需要考慮太多。
該類中還包括其他的一些操作,此處不再概述,詳細參見源碼。四、單元測試
FuncDictionary的單元測試必須涵蓋所有類型的測試才能將代碼覆蓋率達到100%,此處只針對DateTime做正常測試、異常測試和空值測試(當然,對于其他類型的方法,可能還需要做腳本測試,SQL注入測試等,這三種類型的測試是最基本的測試),其他代碼的單元測試詳細見源代碼,也僅僅只做了些基本的測試,寫測試比寫代碼費哥的時間.
五、總結(jié)
以上的代碼僅僅是當時想著怎么實現(xiàn)就怎么寫的,完全是隨意而寫。僅供參考,實戰(zhàn)沒有多大意義,純粹練習下靈感和手感,增強對技術(shù)的敏感性而已,純屬娛樂。對于
<Lexer LexerName="Name0" FontColor="#EE2BA9" CreatedTime="2011-10-25T21:16:18.7866084+08:00" Count="0" Exist="true" LineCommentPrefix="LineCommentPrefix0" StreamCommentPrefix="StreamCommentPrefix0" StreamCommentSuffix="StreamCommentSuffix0" />此類格式的Xml轉(zhuǎn)換和匹配,以上的代碼完全能夠滿足該需求。下一篇將講述另外一種格式的匹配,不過也是通過反射和XmlReader來進行匹配的。
今天也是2011年最后一天,明天就是2012年了,在此恭祝大家2012元旦快樂,新一年,日子順心多平安;新一年,祝福多多又暖暖;新一年,愿望件件都圓滿;新一年,幸?鞓吩鐚崿F(xiàn);新一年,元旦祝福圍身邊;瑪雅終結(jié)之年到了,所以,為了拯救人類,一定要快樂哦!