C 學習筆記 泛型(3) 約束

2021-09-26 14:33:57 字數 3239 閱讀 2338

我們如果在泛型方法中建立泛型的例項,我們會發現它自動帶了四個方法:

這四個方法都是object裡面自動有的方法。由於我們在使用時由於泛型的高度可指定,我們可以為它表明是任何形式,類名、int、string都行,但是我們的自己寫的**邏輯為了執行它的功能,做不到能對任何型別都有很好的相容,所以我們在指定泛型的型別的時候必須對泛型進行約束。

泛型的約束語法,在宣告泛型的行有:where t : type

這裡的where是關鍵字,t是我們指定的泛型,type是我們約束的泛型要讓其指定的型別。

先看個例子:

public delegate int exampledelegate(t t1, t t2);

class program

}class otherclass

}class classa

我們在其中建立了乙個exampledelegate的委託,包裝乙個泛型的方法。

若在泛型方法的邏輯中我們想要用到classa裡面的x,那麼就要使用where來進行泛型的型別約束。使其引數必須為classa型別的引數才能被傳遞.

以上寫的型別約束的形式交轉換型別約束,在c#中用到的型別約束有四種:

那麼我們上面的例子中用到的就是轉換型別引數,下文講乙個個介紹。

引用型別引數即為表明泛型必須為class ,引用型別。型別實參只能是類、介面、字串、委託等型別。例如:

static void main(string args)

public static void example(t obj1) where t : class

這樣就可以確定為引用型別了,當我們把t改為值型別,就會報錯:

這樣就確定了只有引用型別才能當泛型。當然,如果我們使用泛型結構體,使用引用型別約束也可以成立:

public struct examplewhere t : class
我們都知道,struct是值型別的,但是也可以有引用型別的字段和方法。

值型別引數即為表明泛型必須為struct ,值型別。型別實參只能是結構體(int、float、bool)、列舉等型別。

我們可以把上面的例子改一下就可以使用int型傳遞引數了:

class program

public static void example(t obj) where t : struct

}

它的結果是:

建構函式型別約束的「:」後面的值為new(),且這個new ()必須約束的最後面。該約束主要用來檢查實參是否有可用於建立型別例項的無引數建構函式。如果我們傳入的型別有無參的建構函式,它就可以為泛型創造新的例項。

我們寫個例子來測試一下:

class program

public static void example(t obj) where t : new()

}class exampleclass

}

我們使用乙個類,然後建立類的例項傳入泛型方法,方法中約束了t必須有無參的建構函式的形式。如果構造函式呼叫了,將會輸出一句話,結果很顯然:

結果中這句話輸出了兩次,第一次是在主函式裡面宣告了例項,所以輸出,第二次是在泛型方法裡建立了例項,所以也會輸出。

此時,如果我們為exampleclass宣告乙個有參的建構函式,它就會報錯:

這種型別約束常常用在工廠風格的設計模式中,當要有乙個物件在需要時建立另乙個物件時。

指定的t必須可以通過一致性轉換、甚至是裝箱來得到乙個我們指定的型別。可以是我們指定的類和介面。即為我們第乙個例子裡講的那樣,指定乙個類,那麼泛型型別必須為該類的例項或者是子類的例項。而且,這樣的約束支援乙個類和多個介面。

class program

public static void example(t obj) where t : iexampleinte***ce1, new()

}class exampleclass : iexampleinte***ce2

}inte***ce iexampleinte***ce1

inte***ce iexampleinte***ce2 : iexampleinte***ce1

輸出的結果如下,兩次都進行了例項的建立,所以自然構造函式呼叫了兩次。

同樣的,在一些特定型別中也可以通過裝箱進行轉換型別約束:

class program

public static int example(t obj1,t obj2) where t : icomparable

}

我們可以看到,在int型別的定義中明確確定繼承了icomparable介面,所以這裡可以使用該介面的子結構體int,輸出的結果當然a比b小,所以輸出-1。

如果要使用多層約束,那麼這些約束必須是有繼承關係的,而且在這些類和介面中有泛型也必須指明其型別。

轉換型別的約束和建構函式型別約束在工廠設計模式的時候比較常用。

注意,轉換型別約束中的轉換型別不能是以下形式:

由於型別約束可以是多層的,那麼各種約束之間的關係也應該注意。我們可以把型別約束分為主要約束和次要約束。

型別約束的組合中:

但是要注意,struct是可以繼承乙個或多個介面的,所以我們如果定義乙個值型別約束再加乙個介面約束,是完全可以的,而乙個值型別約束再加乙個類約束,由於型別衝突,則顯然不行,如下圖:

c 泛型約束

在定義泛型類時,可以對客戶端 能夠在例項化類時用於型別引數的型別種類施加限制。如果客戶端 嘗試使用某個約束所不允許的型別來例項化類,則會產生編譯時錯誤。這些限制稱為約束。約束是使用 where 上下文關鍵字指定的。下表列出了六種型別的約束 約束說明 t struct 型別引數必須是值型別。可以指定除...

C 泛型約束

約束告知編譯器型別引數必須具備的功能。在沒有任何約束的情況下,型別引數可以是任何型別。編譯器只能假定 system.object 的成員,它是任何 net 型別的最終基類。有關詳細資訊,請參閱使用約束的原因。如果客戶端 嘗試使用約束所不允許的型別來例項化類,則會產生編譯時錯誤。通過使用where上下...

C 泛型約束

一 泛型約束 預設情況下,泛型的型別引數可以是任何型別的。為什麼要使用型別引數的約束呢?簡單點說就是篩選型別引數,在使用泛型的 中如果違反了某個約束不允許的型別來例項化則會產生編譯錯誤,型別引數的約束是使用關鍵字where。下面列出了6中型別的約束 泛型約束有以下幾種 where t base cl...