委託相關
對於委託,我們都知道他是一個引用類型,具有引用類型所具有的通性。需要知道的是它保存的不是實際值,只是是保存對存儲在託管堆中的對象的引用。或說的直接點,委託就相當於叫人幫忙,讓你幫你做一些事情。我這裏就舉一些委託操作的小實例,來簡單的說一下。
在開始舉例之前,再說一下,委託一般包含三個方法,分別是BeginInvoke、EndInvoke、Invoke。EndInvoke就不必說了,一看就知道是幹嘛的。Invoke 和BeginInvoke,前一個是同步委託,後一個是異步委託,何爲同步,何爲異步呢?其實也可從字面意思理解,同步就是同時進行的,不能說你先執行,我後執行,那麼異步就是與同步相對的,但是也不全相對,因爲異步的執行不受主進程的影響,執行全看它個人了。
這裏所說的委託都是自己新建的委託,但還有種委託,是C#控件自帶的委託,也分有同步異步之分,控件委託用處很大,在後面說線程的時候會說到,因爲在使用線程時,有時控件委託是必要的。
下面先單獨說一個委託的例子吧:
第一步:
//創建委託
private delegate void testDelegate();
第二步:
//定義委託API
private event testDelegate TestClick;
public void OnTest()
{
testDelegate handler = TestClick;
if (handler != null)
handler();
}
第三步:
//調用委託API
OnTest();
第四步:
這是委託最常用也是很實用的一個例子,我們可以通過這種方式,實現不同窗體之間的交互,比如在A窗體調用委託API,在B窗口實例化API方法,這樣就能達到在A窗口控制B窗口方法的執行。那麼你可能就會問,我想傳參數怎麼辦,其實很簡單,委託API的傳參與普通方法的傳參類似,只需要在定義委託和API時這樣定義:
注意:
這裏的handler其實類似於 handler.Invoke();,也就是同步委託,調用即執行。那麼異步委託只需要寫成handler.BeginInvoke(null, null);,這是沒有回調函數的異步委託,當然想要調用回調函數,只需如下編寫:
控件創建委託(Control的Invoke和BeginInvoke都執行在主線程即UI線程上)
創建異步委託
private delegate void BeginInvokeDelegate();
private void BeginInvokeMethod(){
//C代碼段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
//A代碼段.......
this.BeginInvoke(new BeginInvokeDelegate(BeginInvokeMethod));
//B代碼段......
}
(1)A在UI線程上執行完後,開始BeginInvoke,BeginInvoke是異步
(2)InvokeMethod方法,即代碼段C不會執行,而是立即在UI線程上執行代碼段B。
(3)代碼段B執行完後(就是說butBeginInvoke_Click方法執行完後),InvokeMethod方法,即代碼段C纔在UI線程上繼續執行。
Thread調用Control的Invoke
private Thread invokeThread;
private delegate void invokeDelegate();
private void StartMethod(){
//C代碼段......
Control.Invoke(new invokeDelegate(invokeMethod));
//D代碼段......
}
private void invokeMethod(){
//E代碼段
}
private void butInvoke_Click(object sender, EventArgs e) {
//A代碼段.......
invokeThread = new Thread(new ThreadStart(StartMethod));
invokeThread.Start();
//B代碼段......
}
1. UI執行A
2. UI開線程InvokeThread,B和C同時執行,B執行在線程UI上,C執行在線程invokeThread上。
3. invokeThread封送消息給UI,然後自己等待,UI處理完消息後,處理invokeThread封送的消息,即代碼段E
4. UI執行完E後,轉到線程invokeThread上,invokeThread線程執行代碼段D
Thread調用Control的BeginInvoke
private Thread beginInvokeThread;
private delegate void beginInvokeDelegate();
private void StartMethod(){
//C代碼段......
Control.BeginInvoke(new beginInvokeDelegate(beginInvokeMethod));
//D代碼段......
}
private void beginInvokeMethod(){
//E代碼段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
//A代碼段.......
beginInvokeThread = new Thread(new ThreadStart(StartMethod));
beginInvokeThread .Start();
//B代碼段......
}
1. UI執行A
2. UI開線程beginInvokeThread,B和C同時執行,B執行在線程UI上,C執行在線程beginInvokeThread上。
3. beginInvokeThread封送消息給UI,然後自己繼續執行代碼D,UI處理完消息後,處理invokeThread封送的消息,即代碼段E
拓展
委託實現異步線程,也可理解爲非UI異步線程,爲啥要我要說可以理解爲非UI異步線程呢,因爲它的委託創建與UI沒有直接關係
#region 非UI異步線程
private object _args;
public delegate void RunHandler(object args);//事件處理委託
private event RunHandler Runs;//委託事件
private event RunHandler CallBackFun;//委託事件
public delegate void CallBackDelegate(RunHandler handler, object args);
CallBackDelegate _d = TakesAWhile;
/// <summary>
/// 執行入口
/// </summary>
/// <param name="run"></param>
/// <param name="callBackFun"></param>
/// <param name="args"></param>
public void DoProcess(RunHandler run, RunHandler callBackFun, object args)
{
Runs = run;
_args = args;
CallBackFun = callBackFun;
//創建有回調函數的異步線程
_d.BeginInvoke(Runs, _args, CallBack, _d);
//創建無回調函數的異步線程
//_d.BeginInvoke(Run, _args, null, null);
}
/// <summary>
/// 定義委託引用的方法
/// </summary>
/// <param name="handler"></param>
/// <param name="args"></param>
private static void TakesAWhile(RunHandler handler, object args)
{
if (handler != null)
{
RunHandler invoke = handler;
invoke(args);
}
}
/// <summary>
/// 定義委託調用完畢後回調函數
/// </summary>
/// <param name="ar"></param>
private void CallBack(IAsyncResult ar)
{
if (ar == null)
{
throw new ArgumentException("ar");
}
CallBackDelegate id = ar.AsyncState as CallBackDelegate;
id.EndInvoke(ar);
if (CallBackFun != null)
{
RunHandler invoke = CallBackFun;
invoke(_args);
}
}
#endregion
這裏只對委託使用做了一部分舉例,更多的用法,大家可以多多實踐,去發現新大陸,我這裏就先不去發現了,因爲接下來準備淺談一下線程。