在前面,我们将设想进行了实现,但是在exception阶段,我们只是粗略跳过,很明显这样是不够的,我们需要自定义的异常处理,同时也更希望明确知道,是哪个线程报错,因此容易想到我们需要对Action[]组中每个Action进行标记,但是肿么标记呢,KeyPair还是Dic?算了为了容易看懂,我们重新定义个新的ActionDictionary类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HarlyApp.BaseFiles
{
public class ActionDictionary
{
public object ActionFlag { get; private set; }
public Action Action { get; private set; }
public ActionDictionary(Action action, object actionFlag)
{
this.Action = action;
this.ActionFlag = actionFlag;
}
}
}
这样了我们需要对CustomizeDispatcher方法作修改,并且暂时自定个最简单的异常处理:
public List<string> exceptionList = new List<string>();
public void CustomizeDispatcher(Action<bool> callbackAction, params ActionDictionary[] actionDics)
{
Func<bool> function = new Func<bool>
(() =>
{
ParallelLoopResult result = Parallel.For(0, actionDics.Length,
(int ac, ParallelLoopState state) =>
{
try
{
actionDics[ac].Action.Invoke();
}
catch
{
exceptionList.Add(actionDics[ac].ActionFlag.ToString() + " Error");
}
});
return !exceptionList.Any();
});
var asyresult = function.BeginInvoke(
(AsyncCallback)((callback)=>
{
callbackAction.Invoke(!exceptionList.Any());
}), null);
function.EndInvoke(asyresult);
}
最后,在调用时候修改成:
public void Display()
{
Stopwatch watch = new Stopwatch();
StringBuilder sb = new StringBuilder();
watch.Start();
this.CustomizeDispatcher(
complete =>
{
watch.Stop();
if (complete)
{
sb.AppendLine(watch.Elapsed.ToString());
MessageBox.Show(sb.ToString());
}
else
{
sb.AppendLine(watch.Elapsed.ToString());
this.exceptionList.ForEach(c => sb.AppendLine(c));
MessageBox.Show(sb.ToString());
}
},
new ActionDictionary(
() =>
{
this.dataaccess.GetItems<ACL_CLASS>().ToList().ForEach(c => this.Classes.Add(c));
int a = 0;
int b = 1 / a;
sb.AppendLine("ClassComplete");
},"Class"),
new ActionDictionary(
() =>
{
this.dataaccess.GetItems<SR_COMPONENT>().ToList().ForEach(c => this.Components.Add(c));
sb.AppendLine("ComponentComplete");
},"Component"),
new ActionDictionary(
() =>
{
this.dataaccess.GetItems<SR_GAMEPLAN>().ToList().ForEach(c => this.GamePlans.Add(c));
sb.AppendLine("GameplanComplete");
}, "Gameplan"));
//this.dataaccess.GetItems<ACL_CLASS>().ToList().ForEach(c => this.Classes.Add(c));
//this.dataaccess.GetItems<SR_COMPONENT>().ToList().ForEach(c => this.Components.Add(c));
//this.dataaccess.GetItems<SR_GAMEPLAN>().ToList().ForEach(c => this.GamePlans.Add(c));
//watch.Stop();
//MessageBox.Show(watch.Elapsed.ToString());
}
看上去很难看,实际实现倒也能实现,因为1/0报错,结果也使正确的,这里对ActionDictionary稍微做点优化,将他变为可回收,并在Dispatcher方法中调用完后就废除:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; namespace HarlyApp.BaseFiles { public class ActionDictionary :IDisposable { public object ActionFlag { get; private set; } public Action Action { get; private set; } private IntPtr handle; private Component Components = new Component(); private bool disposed =false; public ActionDictionary(Action action, object actionFlag) { this.Action = action; this.ActionFlag = actionFlag; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~ActionDictionary() { this.Dispose(false); } protected virtual void Dispose(bool disposing) { // 检查Dispose 是否被调用过. if (!this.disposed) { // 如果等于true, 释放所有托管和非托管资源 if (disposing) { // 释放托管资源. Components.Dispose(); } // 释放非托管资源,如果disposing为 false, // 只会执行下面的代码. CloseHandle(handle); handle = IntPtr.Zero; // 注意这里是非线程安全的. // 在托管资源释放以后可以启动其它线程销毁对象, // 但是在disposed标记设置为true前 // 如果线程安全是必须的,客户端必须实现。 } disposed =true; } [System.Runtime.InteropServices.DllImport("Kernel32")] private extern static Boolean CloseHandle(IntPtr handle); } }
最后的方法就变成了:
public void CustomizeDispatcher(Action<bool> callbackAction, params ActionDictionary[] actionDics) { Func<bool> function = new Func<bool> (() => { ParallelLoopResult result = Parallel.For(0, actionDics.Length, (int ac, ParallelLoopState state) => { try { actionDics[ac].Action.Invoke(); } catch { exceptionList.Add(actionDics[ac].ActionFlag.ToString() + " Error"); } finally { actionDics[ac].Dispose(); } }); return !exceptionList.Any(); }); var asyresult = function.BeginInvoke( (AsyncCallback)((callback)=> { callbackAction.Invoke(!exceptionList.Any()); }), null); function.EndInvoke(asyresult); }
完成后结果也OK鸟