在前面,我们将设想进行了实现,但是在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鸟