无意当中看了一些博文,说有人想自己尝试实现基于异步操作的方法:
1)直接使用Task(不说咯,这个是微软给我们的标准实现方法)。
2)必须继承INotifyCompletion接口,同时自己实现IsCompleted(必须)和Result(可选),GetResult(必须)和OnCompleted(必须)方法:
下面是一个具体的例子(自实现异步函数):
publicinterfaceIAwait<outT>: INotifyCompletion
{boolIsCompleted {get; }
T Result {get; }
T GetResult();
}publicinterfaceIAwaitable<outT>{
IAwait<T>GetAwaiter();
}publicclassAwaitableFunc<T> : IAwaitable<T>{PRivateFunc<T> fun =null;publicIAwait<T>GetAwaiter()
{returnnewInnerAwaitableImplement(fun);
}publicAwaitableFunc(Func<T>func)
{
fun=func;
}privateclassInnerAwaitableImplement : IAwait<T>{privateFunc<T> fun =null;privateboolisFinished=false;privateT result =default(T);publicInnerAwaitableImplement(Func<T>func)
{
fun=func;
}publicboolIsCompleted
{get{returnisFinished;
}
}publicT Result
{get{returnGetResult();
}
}publicvoidOnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem(obj=>{isFinished=true;
continuation();
},null);
}publicT GetResult()
{
result=fun();returnresult;
}
}
}
GetResult和Result属性应该实现同步的方法(阻塞线程的),OnCompleted实现异步方法(必须新线程去处理)。这样的话,一旦主程序这样调用:
AwaitableFunc<int> afunc =newAwaitableFunc<int>(() =>{//模拟一个长时间的任务,注意这里如果用同步机器就死掉Thread.Sleep(5000);return1;
});varresult =afunc.GetAwaiter();
result.OnCompleted(()=>{MessageBox.Show(result.GetResult().ToString());});
你会发现,GetAwaiter方法会先被执行,判断IsCompleted是否为false,如果是false,先执行OnCompleted的方法(作为回调函数一样的性质)先保留,然后开辟新线程执行GetResult(),最后回调到OnCompleted执行回调函数。
你也可以这样调用:
privateasyncvoidbutton1_Click(objectsender, EventArgs e)
{
AwaitableFunc<int> afunc =newAwaitableFunc<int>(() =>{//模拟一个长时间的任务,注意这里如果用同步机器就死掉Thread.Sleep(5000);return1;
});varresult =awaitafunc;MessageBox.Show(result.ToString());}
类似于第一个示例(这里就指出了await其实本质是一个回调函数,编译器自动把await下面的东西全部包含到里边去了,简单叙述原理,注意代码中红色标示部分的位置!)。
其实,GetResult并不是一定需要的,比如这个对int任意进行延时(不直接调用Task.Delay方法,自己写一个呗):
publicclassTimeDelay
{privateint_delayTime =0;publicTimeDelay(intdelayNumber)
{
_delayTime=delayNumber;
}publicInnerAwaitableImplement GetAwaiter()
{returnnewInnerAwaitableImplement(_delayTime);
}publicclassInnerAwaitableImplement:INotifyCompletion
{privateint_delayTime =0;privateboolisFinished=false;publicInnerAwaitableImplement(intdelayTime)
{
_delayTime=delayTime;
}publicboolIsCompleted
{get{returnisFinished;
}
}publicvoidOnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem(obj=>{
Thread.Sleep(_delayTime);
isFinished=true;
continuation();
},null);
}publicvoidGetResult()
{
}
}
}
这样使用:
privateasyncvoidbutton1_Click(objectsender, EventArgs e)
{
TimeDelay afunc=newTimeDelay(2500);awaitafunc;
MessageBox.Show("OK");
}
更简单地——扩展方法:
publicclassTimeDelay
{privateint_delayTime =0;publicTimeDelay(intdelayNumber)
{
_delayTime=delayNumber;
}publicInnerAwaitableImplement GetAwaiter()
{returnnewInnerAwaitableImplement(_delayTime);
}publicclassInnerAwaitableImplement:INotifyCompletion
{privateint_delayTime =0;privateboolisFinished=false;publicInnerAwaitableImplement(intdelayTime)
{
_delayTime=delayTime;
}publicboolIsCompleted
{get{returnisFinished;
}
}publicvoidOnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem(obj=>{
Thread.Sleep(_delayTime);
isFinished=true;
continuation();
},null);
}publicvoidGetResult()
{
}
}
}publicstaticclassIntExtend
{publicstaticTimeDelay.InnerAwaitableImplement GetAwaiter(thisintdelayTime)
{
TimeDelay td=newTimeDelay(delayTime);returntd.GetAwaiter();
}
}
这样调用:
privateasyncvoidbutton1_Click(objectsender, EventArgs e)
{await1000;
MessageBox.Show("OK");
}