手動打造強型(typed)的 DataTable/DataRow
前言
最近正在用 C# 寫一個小視窗軟體 , 裡面會有個功能就是讀取 XML 及寫入 XML , 但我懶 , 想說用 DataSet 來做就好了 , 但後面改了很多次 , 覺得 DataRow 的資料沒有型別 , 後面比較難維護 , 所以去 Google 搜尋看看如何做強型的 DataRow , 當然我找到了 , 不然不會寫這篇 , 這篇是個筆記 , 怕那個網址掛了以後沒得看了 , 原文網址在 : http://www.codeproject.com/KB/database/TypedDataTable.aspx?display=Print
本篇不是要翻譯原文 , 只是我自己整理的筆記自己看得懂就好了 , 有興趣的人直接看原文說明比較詳盡 , 這裡就用一個簡單的讀取及寫入 xml 檔案來做範例
範例說明
假設有一個 XML 檔案格式如下
<?xml version="1.0" encoding="utf-8" ?> <tips> <item><subject>Subject 1</subject><description>Some Text1 ...</description></item> <item><subject>Subject 2</subject><description>Some Text2 ...</description></item> </tips> |
用 DataSet 其實就可以讀取這種格式並且更新內容後寫回 XML 檔案 , 但我們現在要用強型的 DataTable 做
範例程式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | class MyRow : DataRow { /// <summary> /// 讀取及設定標題 /// </summary> public string subject { get { return (string)base["subject"]; } set { base["subject"] = value; } } /// <summary> /// 讀取及設定內容 /// </summary> public string description { get { return (string)base["description"]; } set { base["description"] = value; } } internal MyRow(DataRowBuilder builder) : base(builder) { // 設定預設屬性 columnSubject = string.Empty; columnDescription = string.Empty; } } class MyTable : DataTable { public MyTable() : base("item") { Columns.Add(new DataColumn("subject", typeof(string))); Columns.Add(new DataColumn("description", typeof(string))); } public void Add(MyRow row) { Rows.Add(row); } public void Remove(MyRow row) { Rows.Remove(row); } protected override Type GetRowType() { return typeof(MyRow); } protected override DataRow NewRowFromBuilder(DataRowBuilder builder) { return new MyRow(builder); } // public new MyRow NewRow() // { // MyRow row = (MyRow)NewRow(); // return row; // } public MyRow GetNewRow() { MyRow row = (MyRow)NewRow(); return row; } /// <summary> /// 寫這個可以用陣列方式取得所有的 MyRow /// </summary> /// <param name="idx"></param> /// <returns></returns> public MyRow this[int idx] { get { return (MyRow)Rows[idx]; } } } |
MyTable 及 MyRow 這兩個類別分別繼承自 DataTable 及 DataRow , 現在就可以用下面的方式新增一筆 XML 資料
1 2 3 4 5 6 7 8 9 | DataSet ds = new DataSet(); MyTable table = new MyTable(); ds.ReadXml("test.xml"); ds.Tables.Add(table); MyRow row = table.GetNewRow(); row.subject= "subject 3"; row.description = "description 3"; table.Add(row); ds.WriteXml("test.xml"); |
稍微講解一下
基本上有一些 method 必須複寫(override) , 行 49 , 54 是必須的 , 這樣才有辦法用 MyTable 去產生 MyRow 的型別 , 而行 33 的 base("item") 是為了 XML 範例做的 , 因為每一行資料都是 <item> , 在 DataTable 的 name 就要指定成 "item" , 所以用 base("item") 呼叫 DataTable 的建構子做
行 21 也是必須的 , 我不明白其道理 , 看 MSDN 只知道這個建構子必須要有 , 我想應該和 MyTable.NewRowFromBuilder() 有關係
而在 MyRow 中我定義了 MyRow.subject 及 MyRow.description 分別對應到 XML 的 <subject> 及 <description> 的欄位 , 在 VS.NET 編輯器中就可以自動跳出類別的屬性使用 , 而且編譯時期也會檢查型別
寫的很簡單 , 我覺得應該看原文會比較清楚整個來龍去脈 , 而且原文也有介紹怎麼定義事件 , 講解完B …
近期迴響