在 Windows Phone 中非同步作業比較常見,我的方法很簡單,兩句話。這是第二句,它看上去是這樣的:
MethodCall.Invoke(() => // 這是一個Func<Object>,返回一個結果{ // 這是一個耗時1秒以上的操作,為了獲得一個值,亦或是一個結果集,我寫這個類的目的是我把http請求改寫成了同步,所以這樣會很方便,同樣這個類不僅限於http請求。所有耗時、延時操作都可用。 string result = BigFunction(); // List<string> results = BigFunction();
return result;},(obj) => // 這是一個Action<Object>,處理返回結果{ // 獲得了返回結果,這裡是安全執行緒的,內部使用 Dispatcher.BeginInvoke 來調用 MessageBox.Show(obj.ToString()); // List<string> results = (List<string>)obj;});
另附上 MethodCall.cs
using System;using System.Threading;public static class MethodCall{ static MethodCall() { OnComplate += new ComplateCallBack((obj) => { System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => { _callBack.Invoke(obj); }); }); } private static event ComplateCallBack OnComplate; private delegate void ComplateCallBack(object result); private static Action<object> _callBack; public static void Invoke(Func<object> action, Action<object> callback) { _callBack = callback; ThreadStart t = new ThreadStart(() => { OnComplate(action.Invoke()); }); new Thread(t).Start(); }}
用例說明(2011-11-15 11:50 新增):
因為wp7中只有非同步請求,如果想封裝一個架構實現某些功能,而架構內需要用到http請求,我只能把它寫成同步的,使用線程等待的機制實現了一個擴充方法:
public static class WebRequestExt
{
const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout
public static Stream GetRequestStream(this WebRequest request)
{
using (AutoResetEvent done = new AutoResetEvent(false))
{
RequestState state = new RequestState();
state.request = (HttpWebRequest)request;
request.BeginGetRequestStream((ar) =>
{
RequestState rstate = (RequestState)ar.AsyncState;
rstate.streamResponse = rstate.request.EndGetRequestStream(ar);
done.Set();
}, state);
done.WaitOne(DefaultTimeout);
return state.streamResponse;
}
}
public static HttpWebResponse GetResponse(this WebRequest request, ref string errText)
{
using (AutoResetEvent done = new AutoResetEvent(false))
{
RequestState state = new RequestState();
state.request = (HttpWebRequest)request;
request.BeginGetResponse((ar) =>
{
RequestState rstate = (RequestState)ar.AsyncState;
HttpWebRequest rrequest = state.request;
try
{
rstate.response = (HttpWebResponse)request.EndGetResponse(ar);
Stream responseStream = state.response.GetResponseStream();
rstate.streamResponse = responseStream;
}
catch (Exception e)
{
rstate.exception = e;
}
done.Set();
}, state);
done.WaitOne(DefaultTimeout);
if (state.exception != null)
{
errText = state.exception.Message;
}
return state.response;
}
}
}
internal class RequestState
{
// This class stores the State of the request.
public HttpWebRequest request;
public HttpWebResponse response;
public Stream streamResponse;
public Exception exception;
public RequestState()
{
request = null;
streamResponse = null;
}
}
我在使用的時候就可以像這樣
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.baidu.com/");
string errText = null;
// 這裡直接獲得百度首頁的html
HttpWebResponse response = request.GetResponse(ref errText);
// 這樣的同步方式,而不是使用begin,end模式,再到callback方法中去處理
// IAsyncResult result = request.BeginGetResponse(RequestCallBack, state);
基於這個方法,可以寫出同步的http請求,那麼我在用的時候每次都去new線程不是很方便,所以封裝了這個方法,其實就是省去了一些代碼而已,用的時候可以這樣:
MethodCall.Invoke(
() =>
{
/*
* 實際上這段代碼是在新線程裡執行的,比如在Click事件裡直接這樣寫,也不會阻塞線程
*/
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.baidu.com/");
string errText = null;
// 同步調用GetResponse方法
HttpWebResponse response = request.GetResponse(ref errText);
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
// 返回http請求的結果
return sr.ReadToEnd();
}
},
(obj) =>
{
/*
* 這裡通過MethodCall在內部執行完上面的方法後調用的,obj參數為上面方法的傳回值
*/
// 那麼這裡就可以獲得百度首頁的html了
// 同樣如果上面返回的是一個List<string>或者其他的對象
// 也可以(List<string>)obj或者(xxx)obj來轉換,傳回值是你可以決定的
// 當然這也可以改寫為一個泛型版,類型轉換也不用了
string html = obj.ToString();
MessageBox.Show(html);
});