MSIL入門(四)之委託delegate

2022-01-10 14:00:04 字數 3425 閱讀 5890

委託是一種特殊的引用型別,其設計目的是表示函式指標。所有委託都來自[system.runtime]system.multicastdelegate型別,它又派生自[system.runtime]。委託本身是密封的(就像值型別一樣),因此不能從它們派生型別。

對委託結構施加的限制與對列舉器結構施加的限制一樣嚴格。委託沒有字段、事件或屬性。它們只能有兩個或四個例項方法,並且這些方法的名稱和簽名是預定義的。

委託的兩個強制方法是例項建構函式(.ctor)和invoke。例項建構函式返回void並接受兩個引數;對定義被委託方法的型別的物件引用和對被委託的託管方法的函式指標。

這就引出了乙個問題:如果你能得到乙個函式指標,為什麼你還需要委託呢?為什麼不直接使用函式指標?可以,但是需要引入函式指標型別的字段或變數來儲存這些指標——函式指標型別被認為是安全風險(因為指標值在從特定函式獲得後可以修改),並且被認為是不可驗證的。如果乙個模組是不可驗證的,它在禁用所有安全檢查時,只能從本地驅動器以完全信任模式執行。另乙個缺點是,在呼叫非託管方法時,託管函式指標不能封送到非託管函式指標,而委託可以封送。

第二個強制方法(invoke)必須與委託方法具有相同的簽名。兩個強制的方法(.ctor和invoke)足以允許委託用於同步呼叫,這是在呼叫執行緒被堵塞直到被呼叫方法返回之前通常的方法呼叫。第乙個方法(.ctor)建立委託例項,並將其繫結到被委託的方法。invoke方法用於對delegate方法進行同步呼叫。

當被呼叫的方法在公共語言執行時為此目的而建立的單獨執行緒上執行並且不阻止呼叫執行緒時,委託還可以用於非同步的呼叫。為了能夠被非同步呼叫,委託必須定義兩個額外的方法:begininvokeendinvoke

begininvoke是執行緒啟動程式,它接受委託方法的所有引數加上另外兩個引數:型別為[system.runtime]的委託system.asynccallback表示在呼叫完成時呼叫的**方法,以及選擇用於指示呼叫的最終狀態的物件執行緒。begininvoke返回介面[system.runtime]的例項system.iasyncresult,攜帶作為最後乙個引數傳遞的物件,需要記住的是由於介面、委託和物件都是引用型別,所以當我說「接受委託」或「返回介面」時,實際指的是引用。

如果我們打算在呼叫完成時立即受到通知,則必須指定asynccallback委託。在非同步呼叫完成時呼叫相應的**方法。這種事件驅動技術是對非同步呼叫完成作出反應的最廣泛使用的方法。

我們可以選擇另一種方法來監視非同步呼叫執行緒的狀態:主線程輪詢。返回的介面具有bool get_iscompleted()方法,當非同步呼叫完成時,該方法返回true,我們可以不時地從主線程呼叫此方法,以確定呼叫是否已經完成。

我們可以呼叫返回介面的另乙個方法get_asyncwaithandle,它返回乙個等待控制代碼,乙個[system.runtime]system.threading的例項。waithandle類,在獲得等待控制代碼之後,我們可以用任意自己喜歡的方式監視它(類似於win32 api waitforsingleobject和waitformultipleobjects的使用)。

如果選擇使用輪詢技術,則可以放棄**函式並指定null而不是system.asynccallback委託例項。

endinvoke方法採用[system.runtime]system.iasyncresult介面,由begininvoke作為其單個引數返回,並返回void。此方法等待非同步呼叫完成,從而阻塞呼叫執行緒,因此在begininvoke之後立即呼叫它相當於使用invoke的同步呼叫。最終必須呼叫endinvoke才能清除相應的執行時執行緒表條目,但應該在知道非同步呼叫已完成時執行。

如果選擇使用輪詢技術,則可以放棄**函式,而指定null而不是system.asynccallback委託例項。

endinvoke方法採用[system.runtime]system.iasyncresult介面,由begininvoke返回,作為它的單個引數,並返回void。這個方法等待非同步呼叫完成,阻塞了呼叫執行緒,因此在begininvoke之後立即呼叫它等同於使用invoke進行同步呼叫。最終必須呼叫endinvoke,以清除相應的執行時執行緒表條目,但應該在知道非同步呼叫已經完成時執行。

委託的四個方法都是虛擬的,它們的實現由clr本身提供的,使用者不需要邊寫這些方法的主體。在定義delegate時,我們可以簡單的宣告方法而不提供實現,如下所示:

.class nested public sealed auto ansi

mydelegate

extends [system.runtime]system.multicastdelegate

// end of method mydelegate::.ctor

.method public hidebysig virtual newslot instance int32

invoke(

string s

) runtime managed

// end of method mydelegate::invoke

.method public hidebysig virtual newslot instance class [system.runtime]system.iasyncresult

begininvoke(

string s,

class [system.runtime]system.asynccallback callback,

object 'object'

) runtime managed

// end of method mydelegate::begininvoke

.method public hidebysig virtual newslot instance int32

endinvoke(

class [system.runtime]system.iasyncresult result

) runtime managed

// end of method mydelegate::endinvoke

} // end of class mydelegate

class program

}

參考:《expert .net 2.0 il assembler - serge lidin》

Shell入門(四)之陣列

一 一維陣列 bash支援一維陣列 不支援多維陣列 並且沒有限定陣列的大小。類似與c語言,陣列元素的下標由0開始編號。在shell中,用括號來表示陣列,陣列元素用 空格 符號分割開。array name value0 value1 value2 value3 或array name value0 v...

《xhtml入門系列》之四

1 在乙個頁面中的基本布局元素為 2 如果用css將乙個頁面分為上中下,而中又分為左右 3 如何將多個小控制項排成一排?其實很簡單,比如現在有5個按鈕,要將這些按鈕排成一排,只要作如下處理就可以了 其實就是將每個控制項的float都設定為left就可以了 4 如果不想讓這些東西都排成一排,怎麼辦?那...

Spring框架快速入門之簡介 四

spring框架快速入門之簡介 四 spring 使其保持鬆散 這些介面就位之後,接下來要考慮的就是如何用鬆散耦合方式將它們整合在一起。在清單6中可以看到信用卡帳戶用例的實現。注意,所有的 setter 方法都是由 spring 的配置 bean 實現的。所有的依賴關係 也就是三個介面 都可以由 s...