無心當中看了一些博文,說有人想本身嘗試實現基於異步操做的方法:異步
1)直接使用Task(不說咯,這個是微軟給咱們的標準實現方法)。async
2)必須繼承INotifyCompletion接口,同時本身實現IsCompleted(必須)和Result(可選),GetResult(必須)和OnCompleted(必須)方法:函數
下面是一個具體的例子(自實現異步函數): this
public interface IAwait<out T> : INotifyCompletion { bool IsCompleted { get; } T Result { get; } T GetResult(); } public interface IAwaitable<out T> { IAwait<T> GetAwaiter(); } public class AwaitableFunc<T> : IAwaitable<T> { private Func<T> fun = null; public IAwait<T> GetAwaiter() { return new InnerAwaitableImplement(fun); } public AwaitableFunc(Func<T> func) { fun = func; } private class InnerAwaitableImplement : IAwait<T> { private Func<T> fun = null; private bool isFinished=false; private T result = default(T); public InnerAwaitableImplement(Func<T> func) { fun = func; } public bool IsCompleted { get { return isFinished; } } public T Result { get { return GetResult(); } } public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem(obj => { isFinished = true; continuation(); }, null); } public T GetResult() { result = fun(); return result; } } }
GetResult和Result屬性應該實現同步的方法(阻塞線程的),OnCompleted實現異步方法(必須新線程去處理)。這樣的話,一旦主程序這樣調用:spa
AwaitableFunc<int> afunc = new AwaitableFunc<int>(() => { //模擬一個長時間的任務,注意這裏若是用同步機器就死掉 Thread.Sleep(5000); return 1; }); var result = afunc.GetAwaiter(); result.OnCompleted(() => { MessageBox.Show(result.GetResult().ToString()); });
你會發現,GetAwaiter方法會先被執行,判斷IsCompleted是否爲false,若是是false,先執行OnCompleted的方法(做爲回調函數同樣的性質)先保留,而後開闢新線程執行GetResult(),最後回調到OnCompleted執行回調函數。線程
你也能夠這樣調用:code
private async void button1_Click(object sender, EventArgs e) { AwaitableFunc<int> afunc = new AwaitableFunc<int>(() => { //模擬一個長時間的任務,注意這裏若是用同步機器就死掉 Thread.Sleep(5000); return 1; }); var result = await afunc; MessageBox.Show(result.ToString()); }
相似於第一個示例(這裏就指出了await其實本質是一個回調函數,編譯器自動把await下面的東西所有包含到裏邊去了,簡單敘述原理,注意代碼中紅色標示部分的位置!)。blog
其實,GetResult並非必定須要的,好比這個對int任意進行延時(不直接調用Task.Delay方法,本身寫一個唄):繼承
public class TimeDelay { private int _delayTime = 0; public TimeDelay(int delayNumber) { _delayTime = delayNumber; } public InnerAwaitableImplement GetAwaiter() { return new InnerAwaitableImplement(_delayTime); } public class InnerAwaitableImplement:INotifyCompletion { private int _delayTime = 0; private bool isFinished=false; public InnerAwaitableImplement(int delayTime) { _delayTime = delayTime; } public bool IsCompleted { get { return isFinished; } } public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem(obj => { Thread.Sleep(_delayTime); isFinished = true; continuation(); }, null); } public void GetResult() { } } }
這樣使用:接口
private async void button1_Click(object sender, EventArgs e) { TimeDelay afunc = new TimeDelay(2500); await afunc; MessageBox.Show("OK"); }
更簡單地——擴展方法:
public class TimeDelay { private int _delayTime = 0; public TimeDelay(int delayNumber) { _delayTime = delayNumber; } public InnerAwaitableImplement GetAwaiter() { return new InnerAwaitableImplement(_delayTime); } public class InnerAwaitableImplement:INotifyCompletion { private int _delayTime = 0; private bool isFinished=false; public InnerAwaitableImplement(int delayTime) { _delayTime = delayTime; } public bool IsCompleted { get { return isFinished; } } public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem(obj => { Thread.Sleep(_delayTime); isFinished = true; continuation(); }, null); } public void GetResult() { } } } public static class IntExtend { public static TimeDelay.InnerAwaitableImplement GetAwaiter(this int delayTime) { TimeDelay td = new TimeDelay(delayTime); return td.GetAwaiter(); } }
這樣調用:
private async void button1_Click(object sender, EventArgs e) {await 1000; MessageBox.Show("OK"); }