最近我寫了幾個定時上傳數據的小程序,感覺自己不是程序員,而是代碼搬運工。重複的事情做起來總是很令人煩惱,那有什麼辦法解決這種問題呢?定時執行的功能都是一樣的,只是每個程序需要處理上傳的數據是不一樣的。通俗地說,我就是想寫好定時運行的功能,未來還有定時執行程序的時候,我只要專注實現業務就好了。
這個問題可以使用反射和接口完美的解決。我們在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>
代碼暫時不上傳,如有需要請留言,謝謝!