線程管理類

在Winform中如果所有邏輯都在UI線程執行的話UI很容易就會被卡住轉圈未響應。爲了避免界面卡死,對於費時的操作需要用線程執行。但是有一種情況是我有很多操作都要用線程後臺執行來避免卡界面,但是我又不想多個線程調用無序,要求多個線程調用方法順序執行,來打的UI的順序執行和後臺線程的順序執行。這種情況對多個線程調用的進度管理就成了問題。爲了滿足這種Winform經常需要的情況,開發了線程管理類,後臺管理一個執行隊列,只持有一個線程來執行隊列裏的任務,既滿足了不卡UI的要求,又滿足後臺執行有序的要求。

實現類

///作者:張聯珠
///日期:2014-03-01
///[email protected]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;

namespace LISMonitor
{
    #region 異步工具調用前初始化的委託
    /// <summary>
    /// 初始化異步工具的委託
    /// </summary>
    /// <param name="backGroundWorker">BackgroundWorker</param>
    public delegate void InitAsyUtil(BackgroundWorker backGroundWorker);
    #endregion

    #region 單線程時的後臺執行者
    ///<summary  NoteObject="Class">
    /// [功能描述:內部的後臺工作對象,如果要使後臺有序,幾個工具類都把任務交給該對象] <para/>
    /// [創建者:張聯珠] <para/>
    /// [創建時間:2014年4月11日] <para/>
    ///<說明>
    ///  [說明:修改原工具類
    ///  使用說明:後臺操作方法不要訪問UI資源]<para/>
    ///</說明>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///</summary>
    public static class InnerBackGroundWorker
    {
        /// <summary>
        /// 私有的靜態工作對象
        /// </summary>
        private static BackgroundWorker SelfBackgroundWorker = new BackgroundWorker();

        /// <summary>
        /// 後臺隊列
        /// </summary>
        private static Queue<object[]> WaiteQueue = new Queue<object[]>();

        /// <summary>
        /// 調用鎖
        /// </summary>
        public static object Lock = new object();

        /// <summary>
        /// 運行一個任務,如果線程正忙,任務進入等待
        /// </summary>
        /// <param name="objs"></param>
        public static void RunWorkerAsync(object [] objs)
        {
           lock (WaiteQueue)
           {
            //如果後臺正忙,進入隊列等待
            if (SelfBackgroundWorker.IsBusy || WaiteQueue.Count > 0)
            {
                    WaiteQueue.Enqueue(objs);
            }
            else
            {
                InitAsyUtil initAsyUitil = objs[4] as InitAsyUtil;
                SelfBackgroundWorker = new BackgroundWorker();
                initAsyUitil(SelfBackgroundWorker);
                SelfBackgroundWorker.RunWorkerAsync(objs);
            }
           }
        }

        /// <summary>
        /// 運行任務結束時執行,如果隊列沒有等待的任務,什麼也不做,否則執行下一條任務
        /// </summary>
        /// <param name="objs"></param>
        public static void RunWorkerAsync()
        {
            lock (WaiteQueue)
            {
                //如果隊列中有等待
                if (!SelfBackgroundWorker.IsBusy && WaiteQueue.Count > 0)
                {
                    object[] objs = null;
                    objs = WaiteQueue.Dequeue();
                    SelfBackgroundWorker = new BackgroundWorker();
                    InitAsyUtil initAsyUitil = objs[4] as InitAsyUtil;
                    initAsyUitil(SelfBackgroundWorker);
                    SelfBackgroundWorker.RunWorkerAsync(objs);
                }
            }
        }
    }
    #endregion

    #region 帶返回類型的異步工具
    ///<summary  NoteObject="Class">
    /// [功能描述:管理的異步工具類] <para/>
    /// [創建者:張聯珠] <para/>
    /// [創建時間:2014年4月11日] <para/>
    ///<說明>
    ///  [說明:修改原工具類
    ///  使用說明:後臺操作方法不要訪問UI資源]<para/>
    ///</說明>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///</summary>
    public static class ManagedAsyncUtils<TResult>
    {
        /// <summary>
        /// 私有的靜態工作對象
        /// </summary>
        private static BackgroundWorker SelfBackgroundWorker = null;


        /// <summary>
        /// 使用前出師化異步工具
        /// </summary>
        private static void InitUtil(BackgroundWorker backGroundWorker)
        {
            SelfBackgroundWorker = backGroundWorker;
            SelfBackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
            SelfBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
        }


        /// <summary>
        /// 異步調用
        /// </summary>
        /// <param name="invokeCompleted">回調方法委託()回調的方法可以不是公有的,因爲使用委託了</param>
        /// <param name="businessObject">調用目標對象實例(後臺方法所在類的對象)</param>
        /// <param name="methodName">後臺執行的方法名稱(要申明成公有,應爲內部通過反射來訪問,不是公有的話會訪問不到。該操作方法不要訪問UI資源,在回調方法裏訪問)</param>
        /// <param name="args">後臺執行方法需要的參數(和參數順序一樣的object數組)</param>
        /// <param name="isSelfAsy">是否單獨一個異步</param>
        public static void Invoke(Action<TResult, Exception> invokeCompleted, object businessObject,
            string methodName, object[] args,bool isSelfAsy=false)
        {
            if (!isSelfAsy)
            {
                lock (InnerBackGroundWorker.Lock)
                {
                    InnerBackGroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), isSelfAsy });
                }
            }
            else
            {
                InitUtil(new BackgroundWorker());
                SelfBackgroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), isSelfAsy });
            }
        }

        /// <summary>
        /// BackgroundWorker的後臺方法
        /// </summary>
        /// <param name="sender">事件發送者</param>
        /// <param name="e">參數</param>
        private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //獲得參數數組
            var arguments = e.Argument as object[];
            //獲得回調方法
            var completeMethod = arguments[0];
            //獲得業務實體
            var businessObject = arguments[1];
            //獲得方法名
            var methodName = arguments[2] as string;
            //獲得參數
            var args = arguments[3] as object[];
            //存放結果
            object result = null;
            //存放異常
            Exception ex = null;
            try
            {
                //參數類型集合
                List<Type> lstArgType = new List<Type>();
                //把所有參數的類型填入集合
                if (args != null && args.Length > 0)
                {
                    for (int i = 0; i < args.Length; i++)
                    {
                        lstArgType.Add(args[i].GetType());
                    }
                }
                //獲得方法
                var method = GetTarMethod(businessObject.GetType(), methodName, lstArgType.ToArray());
                //如果沒找到該方法,直接執行該業務實體的方法
                if (method == null)
                {
                    //執行,並把結果賦給結果對象
                    result = businessObject.GetType().GetMethod(methodName, lstArgType.ToArray()).Invoke(businessObject, args);
                }
                //如果找到了方法,則通過接口調方法
                else
                {
                    result = method.Invoke(businessObject, args);
                }
            }
            catch (Exception exThread)
            {
                ex = exThread;
            }
            //結果由參數帶回
            e.Result = new object[] { result, completeMethod, ex, arguments[5] };
        }   

        /// <summary>
        /// 回調方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var results = e.Result as object[];
            //取出結果
            var result = results[0];
            Exception ex = null;
            //如果結果帶出的異常不爲空
            if (results[2] != null)
            {
                var exThread = results[2] as Exception;
                //如果內部異常不爲空,則取內部異常
                if (exThread.InnerException != null)
                {
                    ex = exThread.InnerException;
                }
                //否則直接取總異常
                else
                {
                    ex = exThread;
                }
            }
            try
            {
                //取出回調委託
                Action<TResult, Exception> method = results[1] as Action<TResult, Exception>;
                //如果返回結果爲空,傳該類型的默認值
                if (result == null)
                {
                    method(default(TResult), ex);
                }
                //否則傳帶出的結果
                else
                {
                    method((TResult)result, ex);
                }
            }
            //應對回調時回調對象已被銷燬
            catch (Exception exc)
            {
                //把除了訪問已釋放的資源異常吃掉外,其他異常拋出,方便調試
                if (!(exc is ObjectDisposedException))
                {
                    throw exc;
                }
            }
            finally
            {
                //及時清除引用,防止以後錯誤調用的干擾
                SelfBackgroundWorker = null;
                if(!((bool)results[3]))
                {
                InnerBackGroundWorker.RunWorkerAsync();
                }
            }
        }

        /// <summary>
        /// 獲得目標方法
        /// </summary>
        /// <param name="svcType">方法所在類型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="argTypes">參數類型集合</param>
        /// <returns>方法信息</returns>
        private static MethodInfo GetTarMethod(Type svcType, string methodName, Type[] argTypes)
        {
            //獲取由當前實體所實現的接口集合
            foreach (var item in svcType.GetInterfaces())
            {
                //通過名稱和類型找方法
                var method = item.GetMethod(methodName, argTypes);
                //找到方法就返回
                if (method != null)
                {
                    return method;
                }
            }
            return null;
        }

    }
    #endregion

    #region 不帶返回類型的異步工具
    ///<summary  NoteObject="Class">
    /// [功能描述:管理的異步工具類] <para/>
    /// [創建者:張聯珠] <para/>
    /// [創建時間:2014年4月11日] <para/>
    ///<說明>
    ///  [說明:修改原工具類
    ///  使用說明:後臺操作方法不要訪問UI資源]<para/>
    ///</說明>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///</summary>
    public static class ManagedAsyncUtils
    {
        /// <summary>
        /// 私有的靜態工作對象
        /// </summary>
        private static BackgroundWorker SelfBackgroundWorker = null;


        /// <summary>
        /// 使用前初始化異步工具
        /// </summary>
        public static void InitUtil(BackgroundWorker backGroundWorker)
        {
            SelfBackgroundWorker = backGroundWorker;
            SelfBackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
            SelfBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
        }

        /// <summary>
        /// 異步調用
        /// </summary>
        /// <param name="invokeCompleted">回調方法委託()回調的方法可以不是公有的,因爲使用委託了</param>
        /// <param name="businessObject">調用目標對象實例(後臺方法所在類的對象)</param>
        /// <param name="methodName">後臺執行的方法名稱(要申明成公有,應爲內部通過反射來訪問,不是公有的話會訪問不到。該操作方法不要訪問UI資源,在回調方法裏訪問)</param>
        /// <param name="args">後臺執行方法需要的參數(和參數順序一樣的object數組)</param>
        /// <param name="isSelfAsy">是否單獨一個異步</param>
        public static void Invoke(Action<Exception> invokeCompleted, object businessObject,
            string methodName,object[] args,bool isSelfAsy=false)
        {
            if (!isSelfAsy)
            {
                lock (InnerBackGroundWorker.Lock)
                {
                    InnerBackGroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), isSelfAsy });
                }
            }
            else
            {
                InitUtil(new BackgroundWorker());
                SelfBackgroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), isSelfAsy });
            }
        }

        /// <summary>
        /// 後臺工作方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //提出方法參數
            var arguments = e.Argument as object[];
            //提出回調委託
            var completeMethod = arguments[0];
            //提出調用方法的對象
            var businessObject = arguments[1];
            //提出調用方法的名稱
            var methodName = arguments[2] as string;
            //提出調用方法的參數
            var args = arguments[3] as object[];
            //異常
            Exception ex = null;
            try
            {
                //存所有的參數類型
                List<Type> lstArgType = new List<Type>();
                if (args != null && args.Length > 0)
                {
                    for (int i = 0; i < args.Length; i++)
                    {
                        lstArgType.Add(args[i].GetType());
                    }
                }
                //獲得調用方法
                var method = GetTarMethod(businessObject.GetType(), methodName, lstArgType.ToArray());
                if (method == null)
                {
                    businessObject.GetType().GetMethod(methodName, lstArgType.ToArray()).Invoke(businessObject, args);
                }
                else
                {
                    method.Invoke(businessObject, args);
                }
            }
            catch (Exception exThread)
            {
                ex = exThread;
            }
            //結果由參數帶回
            e.Result = new object[] { completeMethod, ex, arguments[5] };
        }

        /// <summary>
        /// 獲得目標方法
        /// </summary>
        /// <param name="svcType">方法所在類型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="argTypes">參數類型集合</param>
        /// <returns>方法信息</returns>
        private static MethodInfo GetTarMethod(Type svcType, string methodName, Type[] argTypes)
        {
            foreach (var item in svcType.GetInterfaces())
            {
                var method = item.GetMethod(methodName, argTypes);
                if (method != null)
                {
                    return method;
                }
            }
            return null;
        }

        /// <summary>
        /// 回調方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //取出結果
            var results = e.Result as object[];
            try
            {
                //取出回調方法
                var method = results[0] as Action<Exception>;
                if (results[1] != null)
                {
                    var exThread = results[1] as Exception;
                    if (exThread.InnerException != null)
                    {
                        method(exThread.InnerException);
                    }
                    else
                    {
                        method(exThread);
                    }
                }
                else
                {
                    method(null);
                }
            }
            //應對回調時回調對象已被銷燬
            catch (Exception exc)
            {
                //把除了訪問已釋放的資源異常吃掉外,其他異常拋出,方便調試
                if (!(exc is ObjectDisposedException))
                {
                    throw exc;
                }
            }
            finally
            {
                //及時清除引用,防止以後錯誤調用的干擾
                SelfBackgroundWorker = null;
                if (!((bool)results[2]))
                {
                    InnerBackGroundWorker.RunWorkerAsync();
                }
            }
        }
    }
    #endregion

    #region 帶返回類型的異步工具-含報告
    ///<summary  NoteObject="Class">
    /// [功能描述:管理的帶報告帶返回值的異步工具類,對於調用異步時使用單獨線程的操作就千萬不要調用Report方法,因爲單獨線程已經不處於託管環境了,此時調Report會干擾託管的線程] <para/>
    /// [創建者:張聯珠] <para/>
    /// [創建時間:2014年4月11日] <para/>
    ///<說明>
    ///  [說明:修改原工具類
    ///  使用說明:後臺操作方法不要訪問UI資源]<para/>
    ///</說明>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///</summary>
    public static class ManagedAsyncUtilsWithReport<TResult, TReport>
    {
        #region 字段
        /// <summary>
        /// 私有的靜態工作對象
        /// </summary>
        private static BackgroundWorker SelfBackgroundWorker = null;

        /// <summary>
        /// 通知回調
        /// </summary>
        private static Action<TReport, Exception> Reports;
        #endregion

        #region 構造函數

        /// <summary>
        /// 使用前初始化異步工具
        /// </summary>
        public static void InitUtil(BackgroundWorker backGroundWorker)
        {
            SelfBackgroundWorker = backGroundWorker;
            SelfBackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
            SelfBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
            SelfBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
            //支持報告進度
            SelfBackgroundWorker.WorkerReportsProgress = true;
        }
        #endregion

        #region 對外提供的方法
        /// <summary>
        /// 異步調用
        /// </summary>
        /// <param name="invokeCompleted">回調方法委託()回調的方法可以不是公有的,因爲使用委託了</param>
        /// <param name="reportChanged">通知改變的回調方法委託(該參數可以爲空,爲空就不通知改變,如果傳入該參數不爲空,可以調用Report方法來反信息)回調的方法可以不是公有的,因爲使用委託了</param>
        /// <param name="businessObject">調用目標對象實例(後臺方法所在類的對象)</param>
        /// <param name="methodName">後臺執行的方法名稱(要申明成公有,應爲內部通過反射來訪問,不是公有的話會訪問不到。該操作方法不要訪問UI資源,在回調方法裏訪問)</param>
        /// <param name="args">後臺執行方法需要的參數(和參數順序一樣的object數組)</param>
        /// <param name="isSelfAsy">是否單獨一個異步</param>
        public static void Invoke(Action<TResult, Exception> invokeCompleted, Action<TReport, Exception> reportChanged, object businessObject,
            string methodName, object[] args, bool isSelfAsy = false)
        {
            if (!isSelfAsy)
            {
                lock (InnerBackGroundWorker.Lock)
                {
                    InnerBackGroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), reportChanged, isSelfAsy });
                }
            }
            else
            {
                InitUtil(new BackgroundWorker());
                SelfBackgroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), reportChanged, isSelfAsy });
            }
        }

        /// <summary>
        /// 報告事件
        /// </summary>
        /// <param name="reportInfo">報告內容</param>
        /// <param name="ex">報告異常</param>
        public static void Report(TReport reportInfo, Exception ex)
        {
            object[] args = new object[] { reportInfo, ex };
            SelfBackgroundWorker.ReportProgress(0, args);
        }

        #endregion

        #region 內部方法

        /// <summary>
        /// BackgroundWorker的後臺方法
        /// </summary>
        /// <param name="sender">事件發送者</param>
        /// <param name="e">參數</param>
        private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //獲得參數數組
            var arguments = e.Argument as object[];
            //獲得回調方法
            var completeMethod = arguments[0];
            //獲得業務實體
            var businessObject = arguments[1];
            //獲得方法名
            var methodName = arguments[2] as string;
            //獲得參數
            var args = arguments[3] as object[];
            //通知回調
            Reports = arguments[5] as Action<TReport, Exception>;
            //存放結果
            object result = null;
            //存放異常
            Exception ex = null;
            try
            {
                //參數類型集合
                List<Type> lstArgType = new List<Type>();
                //把所有參數的類型填入集合
                if (args != null && args.Length > 0)
                {
                    for (int i = 0; i < args.Length; i++)
                    {
                        lstArgType.Add(args[i].GetType());
                    }
                }
                //獲得方法
                var method = GetTarMethod(businessObject.GetType(), methodName, lstArgType.ToArray());
                //如果沒找到該方法,直接執行該業務實體的方法
                if (method == null)
                {
                    //執行,並把結果賦給結果對象
                    result = businessObject.GetType().GetMethod(methodName, lstArgType.ToArray()).Invoke(businessObject, args);
                }
                //如果找到了方法,則通過接口調方法
                else
                {
                    result = method.Invoke(businessObject, args);
                }
            }
            catch (Exception exThread)
            {
                ex = exThread;
            }
            //結果由參數帶回
            e.Result = new object[] { result, completeMethod, ex, arguments[6] };
        }

        /// <summary>
        /// 回調方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var results = e.Result as object[];
            //取出結果
            var result = results[0];
            Exception ex = null;
            //如果結果帶出的異常不爲空
            if (results[2] != null)
            {
                var exThread = results[2] as Exception;
                //如果內部異常不爲空,則取內部異常
                if (exThread.InnerException != null)
                {
                    ex = exThread.InnerException;
                }
                //否則直接取總異常
                else
                {
                    ex = exThread;
                }
            }
            try
            {
                //取出回調委託
                Action<TResult, Exception> method = results[1] as Action<TResult, Exception>;
                //如果返回結果爲空,傳該類型的默認值
                if (result == null)
                {
                    method(default(TResult), ex);
                }
                //否則傳帶出的結果
                else
                {
                    method((TResult)result, ex);
                }
            }
            //應對回調時回調對象已被銷燬
            catch (Exception exc)
            {
                //把除了訪問已釋放的資源異常吃掉外,其他異常拋出,方便調試
                if (!(exc is ObjectDisposedException))
                {
                    throw exc;
                }
            }
            finally
            {
                //及時清除引用,防止以後錯誤調用的干擾
                SelfBackgroundWorker = null;
                if(!((bool)results[3]))
                {
                    InnerBackGroundWorker.RunWorkerAsync();
                }
            }
        }


        /// <summary>
        /// 進度改變事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //如果通知回調不爲空
            if (Reports != null)
            {
                //提出方法參數
                var arguments = e.UserState as object[];
                Reports((TReport)arguments[0], arguments[1] as Exception);
            }
        }

        /// <summary>
        /// 獲得目標方法
        /// </summary>
        /// <param name="svcType">方法所在類型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="argTypes">參數類型集合</param>
        /// <returns>方法信息</returns>
        private static MethodInfo GetTarMethod(Type svcType, string methodName, Type[] argTypes)
        {
            //獲取由當前實體所實現的接口集合
            foreach (var item in svcType.GetInterfaces())
            {
                //通過名稱和類型找方法
                var method = item.GetMethod(methodName, argTypes);
                //找到方法就返回
                if (method != null)
                {
                    return method;
                }
            }
            return null;
        }
        #endregion

    }


    #endregion

    #region 不帶返回類型的異步工具-含報告
    ///<summary  NoteObject="Class">
    /// [功能描述:管理的的帶報告的異步工具類,對於調用異步時使用單獨線程的操作就千萬不要調用Report方法,因爲單獨線程已經不處於託管環境了,此時調Report會干擾託管的線程] <para/>
    /// [創建者:張聯珠] <para/>
    /// [創建時間:2014年4月11日] <para/>
    ///<說明>
    ///  [說明:修改原工具類
    ///  使用說明:後臺操作方法不要訪問UI資源]<para/>
    ///</說明>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///<修改記錄>
    ///    [修改時間:本次修改時間]<para/>
    ///    [修改內容:本次修改內容]<para/>
    ///</修改記錄>
    ///</summary>
    public static class ManagedAsyncUtilsWithReport<TReport>
    {
        #region 字段
        /// <summary>
        /// 私有的靜態工作對象
        /// </summary>
        private static BackgroundWorker SelfBackgroundWorker = null;

        /// <summary>
        /// 通知回調
        /// </summary>
        private static Action<TReport, Exception> Reports;

        #endregion

        #region 構造函數

        /// <summary>
        /// 使用前初始化異步工具
        /// </summary>
        public static void InitUtil(BackgroundWorker backGroundWorker)
        {
            SelfBackgroundWorker = backGroundWorker;
            SelfBackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
            SelfBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
            SelfBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
            //支持報告進度
            SelfBackgroundWorker.WorkerReportsProgress = true;
        }
        #endregion

        #region 對外提供的方法

        /// <summary>
        /// 異步調用
        /// </summary>
        /// <param name="invokeCompleted">回調方法委託()回調的方法可以不是公有的,因爲使用委託了</param>
        /// <param name="reportChanged">通知改變的回調方法委託(該參數可以爲空,爲空就不通知改變,如果傳入該參數不爲空,可以調用Report方法來反信息)回調的方法可以不是公有的,因爲使用委託了</param>
        /// <param name="businessObject">調用目標對象實例(後臺方法所在類的對象)</param>
        /// <param name="methodName">後臺執行的方法名稱(要申明成公有,應爲內部通過反射來訪問,不是公有的話會訪問不到。該操作方法不要訪問UI資源,在回調方法裏訪問)</param>
        /// <param name="args">後臺執行方法需要的參數(和參數順序一樣的object數組)</param>
        /// <param name="isSelfAsy">是否單獨一個異步</param>
        public static void Invoke(Action<Exception> invokeCompleted, Action<TReport, Exception> reportChanged, object businessObject,
            string methodName, object[] args, bool isSelfAsy=false)
        {
            if (!isSelfAsy)
            {
                lock (InnerBackGroundWorker.Lock)
                {
                    InnerBackGroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil),reportChanged, isSelfAsy });
                }
            }
            else
            {
                InitUtil(new BackgroundWorker());
                SelfBackgroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil),reportChanged ,isSelfAsy });
            }
        }

        /// <summary>
        /// 報告事件
        /// </summary>
        /// <param name="reportInfo">報告內容</param>
        /// <param name="ex">報告異常</param>
        public static void Report(TReport reportInfo, Exception ex)
        {
            object[] args = new object[] { reportInfo, ex };
            SelfBackgroundWorker.ReportProgress(0, args);
        }
        #endregion

        #region 內部方法

        /// <summary>
        /// 後臺工作方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //提出方法參數
            var arguments = e.Argument as object[];
            //提出回調委託
            var completeMethod = arguments[0];
            //提出調用方法的對象
            var businessObject = arguments[1];
            //提出調用方法的名稱
            var methodName = arguments[2] as string;
            //提出調用方法的參數
            var args = arguments[3] as object[];
            //通知回調
            Reports = arguments[5] as Action<TReport, Exception>;
            //異常
            Exception ex = null;
            try
            {
                //存所有的參數類型
                List<Type> lstArgType = new List<Type>();
                if (args != null && args.Length > 0)
                {
                    for (int i = 0; i < args.Length; i++)
                    {
                        lstArgType.Add(args[i].GetType());
                    }
                }
                //獲得調用方法
                var method = GetTarMethod(businessObject.GetType(), methodName, lstArgType.ToArray());
                if (method == null)
                {
                    businessObject.GetType().GetMethod(methodName, lstArgType.ToArray()).Invoke(businessObject, args);
                }
                else
                {
                    method.Invoke(businessObject, args);
                }
            }
            catch (Exception exThread)
            {
                ex = exThread;
            }
            //結果由參數帶回
            e.Result = new object[] { completeMethod, ex, arguments[6] };
        }

        /// <summary>
        /// 獲得目標方法
        /// </summary>
        /// <param name="svcType">方法所在類型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="argTypes">參數類型集合</param>
        /// <returns>方法信息</returns>
        private static MethodInfo GetTarMethod(Type svcType, string methodName, Type[] argTypes)
        {
            foreach (var item in svcType.GetInterfaces())
            {
                var method = item.GetMethod(methodName, argTypes);
                if (method != null)
                {
                    return method;
                }
            }
            return null;
        }



        /// <summary>
        /// 進度改變事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //如果通知回調不爲空
            if (Reports != null)
            {
                //提出方法參數
                var arguments = e.UserState as object[];
                Reports((TReport)arguments[0], arguments[1] as Exception);
            }
        }

        /// <summary>
        /// 回調方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //取出結果
            var results = e.Result as object[];
            try
            {
                //取出回調方法
                var method = results[0] as Action<Exception>;
                if (results[1] != null)
                {
                    var exThread = results[1] as Exception;
                    if (exThread.InnerException != null)
                    {
                        method(exThread.InnerException);
                    }
                    else
                    {
                        method(exThread);
                    }
                }
                else
                {
                    method(null);
                }
            }
            //應對回調時回調對象已被銷燬
            catch(Exception exc)
            {
                //把除了訪問已釋放的資源異常吃掉外,其他異常拋出,方便調試
                if (!(exc is ObjectDisposedException))
                {
                    throw exc;
                }
            }
            finally
            {
                //及時清除引用,防止以後錯誤調用的干擾
                SelfBackgroundWorker = null;
                if (!((bool)results[2]))
                {
                    InnerBackGroundWorker.RunWorkerAsync();
                }
            }
        }

        #endregion
    }
    #endregion
   
}

開啓後臺調用事列

 LIS.Core.Util.LogUtils.WriteDebugLog("準備異步監聽");
 //創建異步工具類的回調委託
 Action<Exception> workerCompleted = new Action<Exception>(DealReturn);
 //創建異步工具類的回調委託
 Action<LogDto, Exception> workerCahnge = new Action<LogDto, Exception>(DealChange);
 //組裝參數
 object[] paras = new object[] { };
 //初始化工具
 ManagedAsyncUtilsWithReport<LogDto>.InitUtil(new BackgroundWorker());
 LIS.Core.Util.LogUtils.WriteDebugLog("監聽程序開啓監聽");
 ManagedAsyncUtilsWithReport<LogDto>.Invoke(workerCompleted, workerCahnge, this, "StartMonitor", paras);                   

回調方法

/// <summary>
/// 處理返回的回調
/// </summary>
/// <param name="ex"></param>
public void DealReturn(Exception ex)
{
    if (ex != null)
    {
        LIS.Core.Util.LogUtils.WriteDebugLog("監聽過程發生錯誤" + ex.Message);
        //對網絡錯誤彈窗提示,並退出程序
        if (ex.Message.Contains("沒有終結點在偵聽可以接受消息的"))
        {
            MessageBox.Show("網絡錯誤,請確認電腦的連網狀態!無法傳輸LIS數據,網絡恢復後請重新打開監聽程序", "iMedicalLIS監聽提示");
        }
        //對網絡錯誤彈窗提示,並退出程序
        if (ex.Message.Contains("無法連接到遠程服務器"))
        {
            MessageBox.Show("網絡錯誤,請確認電腦的連網狀態!無法傳輸LIS數據,網絡恢復後請重新打開監聽程序", "iMedicalLIS監聽提示");
        }
    }
    if (PreDeal.Interface.BaseDeal.DealDataNum > waringNum)
    {
        MessageBox.Show("監聽程序當天調用保存數據次數超過" + waringNum + "次,請聯繫工程師查看是否有異常情況!", "溫馨提示");
    }
    //創建異步工具類的回調委託
    Action<Exception> workerCompleted = new Action<Exception>(DealReturn);

    //創建異步工具類的回調委託
    Action<LogDto, Exception> workerCahnge = new Action<LogDto, Exception>(DealChange);
    //組裝參數
    object[] paras = new object[] { };
    //初始化工具
    ManagedAsyncUtilsWithReport<LogDto>.InitUtil(new BackgroundWorker());
    ManagedAsyncUtilsWithReport<LogDto>.Invoke(workerCompleted, workerCahnge, this, "StartMonitor", paras);
}

/// <summary>
/// 處理數據改變
/// </summary>
/// <param name="ex">異常信息</param>
public void DealChange(LogDto dto, Exception ex)
{
    //窗口是打開狀態才綁數據
    if (this.WindowState != FormWindowState.Minimized)
    {
        //組裝參數
        object[] paras = new object[] { dto.Result };
        this.Invoke(new BindDataDelegate(BindData), paras);
    }
}

線程方法和通知UI

/// <summary>
/// 開始監聽
/// </summary>
public void StartMonitor()
{
	LogDto dt = new LogDto();
    dt.Address = "";
    dt.Time = DateTime.Now.ToString();
	//窗口是打開狀態才綁數據
    if (this.WindowState != FormWindowState.Minimized)
    {
        ManagedAsyncUtilsWithReport<LogDto>.InitUtil(new BackgroundWorker());
        //通知界面改變
        ManagedAsyncUtilsWithReport<LogDto>.Report(dt, null);
    }
    LIS.Core.Util.LogUtils.WriteDebugLog("一輪監聽結束,休眠" + sleepTime + "毫秒");
    //阻塞進程
    System.Threading.Thread.Sleep(sleepTime);
    //有數據改變爲活動圖標
    ChangeIcon(2);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章