.NET反射和接口的混合使用

最近我寫了幾個定時上傳數據的小程序,感覺自己不是程序員,而是代碼搬運工。重複的事情做起來總是很令人煩惱,那有什麼辦法解決這種問題呢?定時執行的功能都是一樣的,只是每個程序需要處理上傳的數據是不一樣的。通俗地說,我就是想寫好定時運行的功能,未來還有定時執行程序的時候,我只要專注實現業務就好了。
這個問題可以使用反射和接口完美的解決。我們在winform界面添加Timer和BackgroundWorker組件,Timer控件用來實現定時,BackgroundWorker控件實現後臺異步執行任務,這種組合能夠完美地解決界面假死的問題。組件使用代碼如下:

private void timer1_Tick(object sender, EventArgs e)
        {
            DateTime dtNow = DateTime.Now;

            if ((this.frenquecyID == "D" && dtNow.Hour == uploadDateTime.Hour && dtNow.Minute == uploadDateTime.Minute && dtNow.Second == uploadDateTime.Second)
                 || (this.frenquecyID == "H" && dtNow.Minute == uploadDateTime.Minute && dtNow.Second == uploadDateTime.Second) 
                 || (this.frenquecyID == "M" && dtNow.Second == uploadDateTime.Second)|| this.frenquecyID == "S")
            {
                if (isRunning) return;

                isRunning = true;//執行中

                this.backgroundWorker1.RunWorkerAsync();
            }
        }

timer控制定時任務執行方式,天、小時、分鐘或者秒爲頻次執行業務。Timer的Tick事件中,我們判斷頻次,判斷當前時間是否與預定的執行時間相同,假如符合頻次和時間相同的條件,我們就異步執行BackgroundWorker的DoWork事件。
我們接下來,看一下BackgroundWorker的DoWork事件實現。

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            operationInterfaceProxy.ProcessData();
        }

看到了嗎?其實很簡單,就是執行業務代理的操作而已。
接下來,我們要看一下接口代理類(OperationInterfaceProxy)的實現,代碼如下所示:

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace TimeOperation
{
    /// <summary>
    /// 處理類
    /// </summary>
    public class OperationInterfaceProxy:OperationInterface.IProcessData
    {
        #region IProcessData 成員
        /// <summary>
        /// 錯誤編碼
        /// </summary>
        private string errorCode = string.Empty;

        /// <summary>
        /// 錯誤編碼
        /// </summary>
        public string ErrorCode
        {
            get { return this.errorCode; }
        }

        /// <summary>
        /// 錯誤信息
        /// </summary>
        private string errorMessage = string.Empty;

        /// <summary>
        /// 錯誤信息
        /// </summary>
        public string ErrorMessage
        {
            get { return this.errorMessage; }
        }

        /// <summary>
        /// 創建接口執行情況文件
        /// </summary>
        Logo log = new Logo(".\\Interface.log");

        /// <summary>
        /// 處理接口
        /// </summary>
        private OperationInterface.IProcessData iProcessData = null;

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="dllFilePath"></param>
        public OperationInterfaceProxy(string dllFilePath)
        {
            try
            {
                log.WriteLogo("開始實例化接口!");

                Assembly a = Assembly.LoadFrom(dllFilePath);

                System.Type[] types = a.GetTypes();

                foreach (System.Type type in types)
                {
                    if (type.GetInterface("IProcessData") != null)
                    {
                        this.iProcessData = (OperationInterface.IProcessData)System.Activator.CreateInstance(type);
                    }
                }

                log.WriteLogo("結束實例化接口!");
            }
            catch (Exception e)
            {
                this.errorMessage = e.Message;
                log.WriteLogo(this.errorMessage);
                return;
            }
        }

        /// <summary>
        /// 數據處理
        /// </summary>
        public void ProcessData()
        {
            if (iProcessData != null)
            {
                iProcessData.ProcessData();
            }
        }

        #endregion
    }
}

這個類是這個程序最關鍵所在。我們用到了接口,用到了反射。第一步OperationInterfaceProxy類實現接口OperationInterface.IProcessData

第二步,定義接口屬性

 /// <summary>
        /// 處理接口
        /// </summary>
        private OperationInterface.IProcessData iProcessData = null;

第三步,也是最爲關鍵的一步,就是在構造函數中用反射的方式讀取實現的接口類

/// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="dllFilePath"></param>
        public OperationInterfaceProxy(string dllFilePath)
        {
            try
            {
                log.WriteLogo("開始實例化接口!");

                Assembly a = Assembly.LoadFrom(dllFilePath);

                System.Type[] types = a.GetTypes();

                foreach (System.Type type in types)
                {
                    if (type.GetInterface("IProcessData") != null)
                    {
                        this.iProcessData = (OperationInterface.IProcessData)System.Activator.CreateInstance(type);
                    }
                }

                log.WriteLogo("結束實例化接口!");
            }
            catch (Exception e)
            {
                this.errorMessage = e.Message;
                log.WriteLogo(this.errorMessage);
                return;
            }
        }

下邊句話是加載程序集

Assembly a = Assembly.LoadFrom(dllFilePath);

獲取程序集的類型

System.Type[] types = a.GetTypes();

創建一個實例並賦值給定義接口屬性

this.iProcessData = (OperationInterface.IProcessData)System.Activator.CreateInstance(type);

第四步,就是實現操作類,這個很簡單,如下代碼

/// <summary>
        /// 數據處理
        /// </summary>
        public void ProcessData()
        {
            if (iProcessData != null)
            {
                iProcessData.ProcessData();
            }
        }

這種方式真的很好用,實現了我們事先定義的接口,在配置文件裏面設置DLLNAME參數就可以正常使用了,如下xml 所示:

<?xml version="1.0" encoding="UTF-8"?>
<Items>
  <BEGINDATE>2015-08-01</BEGINDATE>
  <INTERVAL>1000</INTERVAL>
  <UPLOADTIME>2015-08-01 09:08:20</UPLOADTIME>
  <CLINICDAYS>3</CLINICDAYS>
  <FREQUENCY>S</FREQUENCY>
  <DLLNAME>test.dll</DLLNAME>
  <TITLE>我的定時上傳</TITLE>
</Items>

代碼暫時不上傳,如有需要請留言,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章