最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

第 48 講:委托(一):委托類型的概念

2021-07-15 08:17 作者:SunnieShine  | 我要投稿

下面我們進入一個新的板塊:委托(Delegate)。委托也是一種類型,不過和之前的類、結(jié)構(gòu)和接口不太一樣,委托的書寫格式完全不像是那樣,它只需要一句話就可以聲明一個委托類型:

是的,這一點長得相當(dāng)像是方法的簽名。唯一的區(qū)別是,委托類型的聲明帶有 delegate 這個新的關(guān)鍵字。

要說明清楚委托類型是干嘛的,我們先來看一個引例。

Part 1 引例

我們先來介紹一個例子。假設(shè)我們需要對一個數(shù)組進行排序。

我們簡單使用冒泡排序法完成這項任務(wù),因為它寫起來比較簡單。那么調(diào)用這個方法也很容易:

對吧。

那么我們來一個新的問題。假設(shè)我們想要告訴這個排序函數(shù) Sort“按照我自己的行為來排序”,而不是必須要分得從小到大的升序排序,那么怎么做呢?最簡單的情況是,我們假設(shè)需要降序排序了的話,我們肯定需要改變 if 條件,從 >= 改成 <=,對吧。

可問題在于,我不想復(fù)制粘貼,我想就在這一個方法里解決升序降序兩種操作;而這樣的行為我只需要改變一下 if 的執(zhí)行,是不是就可以了?

最容易想到的辦法就是給這個 Sort 方法添加一個參數(shù),專門表示升序還是降序。那么,最容易想到的就是一個枚舉類型,包含升降序兩種情況的字段:

然后,我們把 OrderingType 類型當(dāng)作參數(shù)傳入:

我們僅僅需要調(diào)整的是條件。其中 type 參數(shù)按照兩種排序模式進行排序。如果是升序,那么 condition 變量表示的就是是否前者大于等于后者;如果是降序,那么 condition 變量表示的是是否前者小于等于后者。

當(dāng)然,因為 type 完全有可能超出范圍,因此我們需要驗證是不是 type 超出范圍。如果 type 既不是 Ascending 也不是 Descending 的話,那么就拋異常來終止程序并告知用戶調(diào)用錯誤。

雖然代碼稍微多了一點,但實際上都是必要的。于是,這樣的話,我們僅需要通過傳入?yún)?shù) OrderingType 類型的變量就可以達到效果了:

不過,它還不夠靈活。因為僅是升序或降序的話,就完全不能按照自己的方式來排序。倘若我們傳入的數(shù)組并不是 int 類型而是 string 類型的數(shù)組的話,升序降序是參照什么規(guī)則來排序呢?是字符串長度?還是字典序?還是其它的?

此時我們僅通過一個枚舉類型就無法得到想要的靈活的結(jié)果。這個時候,我們可以試著考慮一種情況。能不能我們以方法為單位傳入?yún)?shù)呢?假設(shè),我們這個方法里給出的是兩個數(shù)的自定義比較關(guān)系,這樣的話,是不是就可以達到“自定義排序行為來排序”的目的了呢?可是,怎么樣才能允許把方法當(dāng)參數(shù)傳入呢?這個時候我們需要用到的是委托類型。下面我們來介紹一下如何使用委托類型。

Part 2 委托類型的使用

考慮一下,我們需要兩個數(shù)字才能比較大小,如果是字符串的話,那么就需要兩個 string 類型的對象來參與比較,最終得到一個比較結(jié)果來指示到底左邊大還是右邊大。那么,這個方法的簽名一定是兩個 string 類型的變量當(dāng)參數(shù),而帶有一個 int 類型的數(shù)據(jù)當(dāng)結(jié)果。為什么是 int 類型呢?因為可能有三種情況:左邊大、右邊大或相等。如果單純使用 bool 可能就不能考慮到一樣大的時候的情況。因此用 int 合適一點。當(dāng)然你用 byte 這些類型也可以。

我們先定義一個委托類型。

注意這里的書寫格式當(dāng)成方法一樣,只需要在方法的簽名的開頭補上訪問修飾符和 delegate 關(guān)鍵字就可以了。

我們把這里的 Comparison 稱為委托類型名。也就是說這個是名為 Comparison 的委托類型。接著,我們把它當(dāng)成參數(shù)傳入到 Sort 方法里:

第二步完成。下面是第三步:實現(xiàn) Sort 方法的代碼。顯然,別的地方都不用改,和之前用枚舉類型作為升降序指示,改變 if 條件的內(nèi)容一樣,這里也只需要改變 if 條件即可:

注意改造后的第 7 行代碼。我們在 comparison 變量后加上了一個新的調(diào)用寫法:.Invoke()。單詞 invoke 的意思是“調(diào)用”,然后按照原本 Comparison 類型規(guī)定的參數(shù),按次序把參數(shù)傳進去。因為 Comparison 類型需要兩個 string 類型的對象作為參數(shù),因此我們只需要按照以前排序比較的這倆數(shù)據(jù),傳進去就可以了。

接著,我們把整個表達式 comparison.Invoke(array[j], array[j + 1]) 當(dāng)成一個方法的調(diào)用。因為 Comparison 類型返回值是 int 類型,因為我們后面需要加上一個比較部分:>= 0,以表示排序結(jié)果是不是大于 0。按照前文的約定,我們把 > 0 稱為“左邊大”,而 < 0 稱為“右邊大”;== 0 則表示“一樣大”。

這是第三步。那么整個方法的設(shè)計和書寫過程我們就解決了。下面我們來說一下這樣的方法的調(diào)用過程。

請注意第 3、4 行代碼以及第 9 到第 25 行代碼。第 9 到 25 行代碼給出了一個叫做 Compare 的方法,里面指定了兩個 string 類型的對象參與比較。首先是看字符串長度。長度更長的字符串更大;如果字符串長度一樣的話,就逐個比較字符。如果對應(yīng)位的字符,ASCII 碼較大的話,那么字符串較大;如果全部對應(yīng)位置上也都是一樣的字符的話,長度一樣字符也都一樣就說明字符串是一樣的,那么我們就返回 0 表示一樣。

稍微注意一點的是,因為這個方法是稍后會用的方法,所以它的參數(shù)類型和返回值類型必須和之前委托類型的簽名(倆 string 類型對象當(dāng)參數(shù),返回 int 類型結(jié)果)要保持一致。

整體這個 Compare 方法就指定了一個字符串的自定義比較過程。你甚至可以定義規(guī)則改成別的排序規(guī)則,這里這么寫僅用于作參考。接著,我們看下第 3 行的代碼。第 3 行是把 Comparison 類型當(dāng)成了一個可以實例化的類或者結(jié)構(gòu)的語法來做了。我們直接通過 new 來實例化一個 Comparison 類型的對象,傳入了一個方法名,叫做 Compare。這就是我們剛才寫的自定義的排序規(guī)則的方法。

這是一個固定語法。委托類型剛好允許我們直接把方法名當(dāng)參數(shù)傳遞到實例化 Comparison 類型的語句里去當(dāng)參數(shù)。接著,我們實例化后的 Comparison 實例是這里的 comparisonMethod。拿到這個實例后,我們就可以直接把這個實例當(dāng)成參數(shù)傳遞到 Sort 方法里了。因為 Sort 方法剛好第二個參數(shù)就是需要 Comparison 類型的對象,這里我們傳入了它就完全是契合的。

整體,我們就把委托類型的書寫格式、使用方式就說完了。整個程序就是這個樣子的感覺,運行起來也不會有問題,按照剛才規(guī)定的“字符串長度較長的更大、字符串對應(yīng)位字符 ASCII 碼較大的更大”的規(guī)則來排序的。

Part 3 委托類型的繼承關(guān)系

可見,委托類型可以實例化,雖然語法很奇怪,但仍然是用的 new 語句。那么委托類型完全可以稱得上是一種類型。那么,委托類型既然是類型,總得有一個繼承關(guān)系吧。像是之前的接口、類這些東西,雖然有些可以自定義繼承關(guān)系有些不能,但它們總歸是有一個層次關(guān)系的。委托類型呢?

委托類型是一種引用類型,因為它自身的處理機制的問題,它被設(shè)計為一種引用類型。從底層來說,它是一種特殊的類,只是這個類特殊到你無法通過 C# 的基本語法來完美描述和表達出來這個委托類型的細節(jié)。正是因為它無法被 C# 語法表達,所以它單獨被作為一個類型看待。委托類型既然是一種特殊的類,那么它必然會有派生和繼承關(guān)系。

實際上,委托類型設(shè)計得也很復(fù)雜。和普通的繼承還有點不一樣,你看結(jié)構(gòu)從 ValueType 類型派生、類和接口直接從 object 派生、枚舉從 Enum 派生、數(shù)組從 Array 派生,都是只有一級之差的關(guān)系。但是委托類型卻有點不同。實際上,我們設(shè)計的自定義委托類型全部從一個叫 MulticastDelegate 的類型派生,而這個類型是個抽象類。然后,這個 MulticastDelegate 抽象類又從一個叫 Delegate 的抽象類派生下來的。所以委托類型實際上有兩級的差別。

這樣一來,繼承關(guān)系就比較清楚了。

Part 4 invoke 是什么意思?

前面我們用到了 .Invoke 的調(diào)用,不過 invoke 這個單詞是什么意思呢?“調(diào)用”。英語里 invoke 和 call 都可以翻譯成“調(diào)用”,但它們的使用場景是不同的。invoke 表示委托某個人去做某個事情,call 則是自己上,直接去做。invoke 往往會給人一種感覺,我委托了別人做這個事情,那么做的事情的過程、結(jié)果這些東西一定會由委托人最后反饋給我,而 call 則不會這樣。所以有些地方也把 invoke 理解成回調(diào)(Callback),而把調(diào)用的時候調(diào)用的那個函數(shù)(方法)稱為回調(diào)函數(shù)(Callback Function)。比如我們委托類型的對象包裝起來的那個 Compare 方法,我們就稱為回調(diào)函數(shù)。這個是一個術(shù)語詞,所以本來是叫“回調(diào)方法”的,但是因為是術(shù)語所以仍用的是“回調(diào)函數(shù)”這個說法。

Invoke 還有一層意思是觸發(fā)(Trigger),也就是說這個過程并不會當(dāng)場使用,而是在某個特定的場合觸發(fā)。使用我們之前的代碼,我們可以看到,實際上委托類型的對象是把一個函數(shù)包裝包裹在了里面,等待合適的時候,我們使用了 .Invoke 調(diào)用的時候,這個方法才會調(diào)用起來。所以這個時候是觸發(fā)的概念。

那什么叫 call 呢?Sort(arr, comparisonMethod); 里的 Sort 得到了調(diào)用,這個叫 call,因為它是直接調(diào)用的。

下一節(jié)我們會說明繼承關(guān)系下的這個 MulticastDelegate 到底是什么,然后再說一下 Delegate 是什么,以及委托的加減法。下一講的內(nèi)容可能偏難,但是也是必須要學(xué)的一部分,一定要打開思維。


第 48 講:委托(一):委托類型的概念的評論 (共 條)

分享到微博請遵守國家法律
平昌县| 临潭县| 珠海市| 黄陵县| 葵青区| 延长县| 都安| 吴忠市| 宁波市| 泰和县| 柞水县| 承德县| 上饶县| 夹江县| 南陵县| 南丰县| 天长市| 麻栗坡县| 洛阳市| 黄大仙区| 柘荣县| 湘阴县| 拉萨市| 定远县| 昌吉市| 阜城县| 丹寨县| 西青区| 四子王旗| 吴江市| 交口县| 扬州市| 团风县| 绵阳市| 和政县| 霸州市| 湖州市| 大关县| 湖南省| 廊坊市| 隆化县|