泛型型別參數的條件約束 (C++/CLI)
在泛型類型或方法宣告中,您可以使用條件約束來限定類型參數。 條件約束是做為類型引數使用的類型必須符合的需求。 例如,條件約束可能是指,類型引數必須實作特定介面或從特定類別繼承。
條件約束是選擇性的;在參數上未指定條件約束相當於使用 Object 條件約束。
語法
where
type-parameter
:
constraint-list
參數
type-parameter
要限制的其中一個型別參數標識碼。
constraint-list
條件約束規格的逗號分隔清單。 清單可以包含 要由實作的 type-parameter
介面。
清單也可以包括類別。 若要滿足基類條件約束,類型自變數必須與條件約束相同,或衍生自條件約束。 指定 ref class
表示類型自變數必須是參考型別,包括任何 class
、 interface
、 delegate
或 array
型別。 指定 value class
表示類型自變數必須是實值型別。 您可以指定 Nullable<T>
以外的任何實值型別。
您也可以指定 gcnew()
來指出類型自變數必須具有公用無參數建構函式。
您也可以指定泛型參數做為條件約束。 您限制的類型所提供的類型自變數必須是或衍生自條件約束的類型。 此參數稱為 裸體類型條件約束。
備註
條件約束子句由 where
後面接著類型參數、冒號 (:
) 和條件約束所組成,指定類型參數限制的本質。 where
是即時線上關鍵字。 如需詳細資訊,請參閱 上下文相關關鍵詞。 使用空格分隔多個 where
子句。
條件約束套用至型別參數後,就會對可做為泛型類型或方法的引數使用的類型加以限制。
類別和介面條件約束會指定,引數類型必須是或繼承自指定的類別,或是實作指定的介面。
將條件約束應用至泛型類型或方法,可讓該類型或方法中的程式碼利用條件約束類型的已知功能。 例如,您可以宣告泛型類別,讓型別參數能夠實作 IComparable<T>
介面:
// generics_constraints_1.cpp
// compile with: /c /clr
using namespace System;
generic <typename T>
where T : IComparable<T>
ref class List {};
這個限制式要求用於 T
的引數在編譯時間實作 IComparable<T>
。 另外也允許呼叫介面方法,例如 CompareTo
。 呼叫介面方法時,不需要再類型參數的執行個體上進行轉型。
無法透過類型參數呼叫類型自變數類別中的靜態方法;它們只能透過實際的具名類型呼叫。
條件約束不能是實值型別,包括 內建型別,例如 int
或 double
。 因為實值型別不能有衍生類別,所以只有一個類別可以滿足條件約束。 在這種情況下,可以重新撰寫泛型,將型別參數取代為特定實值類型。
在某些情況下需要條件約束,因為編譯程式不允許使用未知類型的方法或其他功能,除非條件約束暗示未知類型支援方法或介面。
同一個類型參數的多個條件約束可以使用逗號分隔清單指定。
// generics_constraints_2.cpp
// compile with: /c /clr
using namespace System;
using namespace System::Collections::Generic;
generic <typename T>
where T : List<T>, IComparable<T>
ref class List {};
若有多個型別參數,請對每個型別參數使用一個 where 子句。 例如:
// generics_constraints_3.cpp
// compile with: /c /clr
using namespace System;
using namespace System::Collections::Generic;
generic <typename K, typename V>
where K: IComparable<K>
where V: IComparable<K>
ref class Dictionary {};
根據下列規則,在您的程式代碼中使用條件約束:
如果列出了多個條件約束,條件約束可依照任意順序列出。
條件約束也可以是類別類型,例如抽象基底類別。 不過,條件約束不能是實值型別或
sealed
類別。條件約束本身不能是型別參數,但它們可以牽涉到開放式建構型別中的型別參數。 例如:
// generics_constraints_4.cpp // compile with: /c /clr generic <typename T> ref class G1 {}; generic <typename Type1, typename Type2> where Type1 : G1<Type2> // OK, G1 takes one type parameter ref class G2{};
範例
下列範例將示範在類型參數上使用條件約束呼叫執行個體方法。
// generics_constraints_5.cpp
// compile with: /clr
using namespace System;
interface class IAge {
int Age();
};
ref class MyClass {
public:
generic <class ItemType> where ItemType : IAge
bool isSenior(ItemType item) {
// Because of the constraint,
// the Age method can be called on ItemType.
if (item->Age() >= 65)
return true;
else
return false;
}
};
ref class Senior : IAge {
public:
virtual int Age() {
return 70;
}
};
ref class Adult: IAge {
public:
virtual int Age() {
return 30;
}
};
int main() {
MyClass^ ageGuess = gcnew MyClass();
Adult^ parent = gcnew Adult();
Senior^ grandfather = gcnew Senior();
if (ageGuess->isSenior<Adult^>(parent))
Console::WriteLine("\"parent\" is a senior");
else
Console::WriteLine("\"parent\" is not a senior");
if (ageGuess->isSenior<Senior^>(grandfather))
Console::WriteLine("\"grandfather\" is a senior");
else
Console::WriteLine("\"grandfather\" is not a senior");
}
"parent" is not a senior
"grandfather" is a senior
當泛型型別參數作為條件約束使用時,它稱為 裸體類型條件約束。 當具有自己的型別參數之成員函式需要將該參數限制為包含類型的型別參數時,巢狀類型條件約束就很有用。
在下列範例中,T
是 Add
方法內容中的 Naked 型別限制式。
巢狀類型參數也可以在泛型類別定義中使用。 巢狀類型條件約束對泛型類別來說並不那麼實用,因為編譯器除了會假設巢狀類型約束條件衍生自 Object 之外,不會再做其他任何假設。 如果您要強制兩個型別參數之間具有繼承關係,請在泛型類別上使用巢狀類型條件約束。
// generics_constraints_6.cpp
// compile with: /clr /c
generic <class T>
ref struct List {
generic <class U>
where U : T
void Add(List<U> items) {}
};
generic <class A, class B, class C>
where A : C
ref struct SampleClass {};