實作泛型版本的XML資料讀寫器

在實務上,目前自行開發一個泛型類別或函式的機會的確是不多。能想的到的範例,大致上就是利用XMLSerializer來序列化物件時可以改寫成泛型的版本吧。

利用XMLSerializer我們可以將任何型別的物件(當然會有些基本限制)給轉換成XML的格式,並儲存到檔案中。
在第一個版本中,我們實作了一個XMLPersistence類別,其中有兩個靜態函式Load()及Save(),可用來將型別為MySettings的物件儲存到指定的檔名中,或是由指定的檔名中讀取出來,還原成一個MySettings的物件。
XMLPersistence.Test()是用來測試的程式碼。說明如何使用XMLPersistence這個類別。
在做完第一版後,可以發現Load()跟Save()這兩個函式中,其實我們如果能將MySettings這個型別抽離出來,作為一個參數的話,那Load()跟Save()這兩個函式就可以改寫成泛型的函式。不論你需要儲存或讀出的型別的哪一種,都可以透過這兩個泛型函式來儲存成xml檔,或是由xml讀出轉回成物件。

程式碼下載:XMLPersistence.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace UT
{
    /// <summary>
    /// 要用來儲存成xml檔案的類別
    /// </summary>
    public class MySettings
    {
        public string DBName = "";
        public string ServerIP = "";
        public string User = "";
        public string Password = "";

        /// <summary>
        /// xml persistence時需要預設建構子
        /// </summary>
        public MySettings()
        {
        }

        public MySettings(string dbName, string serverIP, string user, string password)
        {
            DBName = dbName;
            ServerIP = serverIP;
            User = user;
            Password = password;
        }

        public override string ToString()
        {
            return string.Format("DBName : {0}, ServerIP : {1}, User : {2}, Password : {3}",
                DBName, ServerIP, User, Password);
        }
    }

    /// <summary>
    /// 第一版:只能處理MySettings的型別
    /// </summary>
    public class XMLPersistence
    {
        #region xml檔案存取
        public static MySettings Load(string xmlFile )
        {
            StreamReader sr = null;
            try
            {
                XmlSerializer xmlReader = new XmlSerializer(typeof(MySettings));
                sr = new StreamReader(xmlFile, System.Text.Encoding.Default);
                object tmp = xmlReader.Deserialize(sr);
                if (tmp is MySettings)
                {
                    return tmp as MySettings;
                }
                else
                    return null;
            }
            catch (Exception exp)
            {
                return null;
            }
            finally
            {
                if( sr != null )
                    sr.Close();
            }
        }

        public static bool Save(string xmlFile, MySettings xmlData )
        {
            StreamWriter sw = null;

            try
            {
                XmlSerializer xmlWriter = new XmlSerializer(typeof(MySettings));
                sw = new StreamWriter(xmlFile, false, System.Text.Encoding.Default);
                xmlWriter.Serialize(sw, xmlData );

                return true;
            }
            catch (Exception exp)
            {
                return false;
            }
            finally
            {
                if( sw != null )
                    sw.Close();
            }
        }
        #endregion

        public static void Test()
        {
            MySettings setting = new MySettings( "PositionV4", "10.6.228.81", "user", "pwd" );

            string filename = "TestXML.xml";
            if (XMLPersistence.Save(filename, setting) == false)
            {
                Console.WriteLine("儲存xml失敗");
                return;
            }

            MySettings loadFromXml = XMLPersistence.Load(filename);
            if (loadFromXml != null)
            {
                Console.WriteLine(loadFromXml.ToString());
            }
            else
            {
                Console.WriteLine("載入xml失敗"); 
            }
            
        }
    }

    /// <summary>
    /// 泛型版:可處理多種型別
    /// </summary>
    public class GenericXMLPersistence
    {
        #region xml檔案存取
        /// <summary>
        /// 加入class的條件式,是因為要使用到as 
        /// 加入new()的條件式,是因為xml可讀寫的類別要有預設建構子
        /// </summary>
        /// <typeparam name="TSetting"></typeparam>
        /// <param name="xmlFile"></param>
        /// <returns></returns>
        public static TSetting Load<TSetting>(string xmlFile) where TSetting : class,new()
        {
            StreamReader sr = null;
            try
            {
                XmlSerializer xmlReader = new XmlSerializer(typeof(TSetting));
                sr = new StreamReader(xmlFile, System.Text.Encoding.Default);
                object tmp = xmlReader.Deserialize(sr);
                if (tmp is TSetting)
                {
                    return tmp as TSetting;
                }
                else
                    return null;
            }
            catch (Exception exp)
            {
                return null;
            }
            finally
            {
                if (sr != null)
                    sr.Close();
            }
        }

        public static bool Save<TSetting>(string xmlFile, TSetting xmlData) where TSetting : new()
        {
            StreamWriter sw = null;

            try
            {
                XmlSerializer xmlWriter = new XmlSerializer(typeof(TSetting));
                sw = new StreamWriter(xmlFile, false, System.Text.Encoding.Default);
                xmlWriter.Serialize(sw, xmlData);

                return true;
            }
            catch (Exception exp)
            {
                return false;
            }
            finally
            {
                if (sw != null)
                    sw.Close();
            }
        }
        #endregion

        public static void Test()
        {
            MySettings setting = new MySettings("PositionV4", "10.6.228.81", "user", "pwd");

            string filename = "TestXML.xml";
            if (GenericXMLPersistence.Save(filename, setting) == false)
            {
                Console.WriteLine("儲存xml失敗");
                return;
            }

            // 這裏不能使用編譯器自動推論的方式,因為傳回值型別不會在進行型別推論時被使用到。
            // 所以要明確指定型別
            MySettings loadFromXml = GenericXMLPersistence.Load<MySettings>(filename);
            if (loadFromXml != null)
            {
                Console.WriteLine(loadFromXml.ToString());
            }
            else
            {
                Console.WriteLine("載入xml失敗");
            }

        }
    }
}

留言

這個網誌中的熱門文章

DOS Batch指令檔中如何記錄log資訊

用捷徑方式執行需帶入命令列參數的Windows Form程式

使用regular expression來match中括號(square bracket)