Ограничения, применяемые к параметрам универсальных типов (C++/CLI)Constraints on Generic Type Parameters (C++/CLI)

В объявлениях универсального типа или метода можно указывать параметр типа с ограничениями.In generic type or method declarations, you can qualify a type parameter with constraints. Ограничение — это требование, которому должны удовлетворять типы, используемые в качестве аргументов типа.A constraint is a requirement that types used as type arguments must satisfy. Например, ограничение может требовать, чтобы аргумент типа реализовывал определенный интерфейс или наследовался от определенного класса.For example, a constraint might be that the type argument must implement a certain interface or inherit from a specific class.

Ограничения не являются обязательными; отсутствие ограничения на параметр эквивалентно ограничению этого параметра значением Object.Constraints are optional; not specifying a constraint on a parameter is equivalent to constraining that parameter to Object.

СинтаксисSyntax

where type-parameter: constraint list

ПараметрыParameters

Тип-параметрtype-parameter
Один из ограниченных параметров типа.One of the type parameters, to be constrained.

constraint listconstraint list
constraint list — это разделенный запятыми список спецификаций ограничений.constraint list is a comma-separated list of constraint specifications. Этот список может содержать интерфейсы, которые должны быть реализованы параметром типа.The list can include interfaces to be implemented by the type parameter.

Список также может содержать класс.The list can also include a class. Чтобы аргумент типа удовлетворял ограничению базового класса, он должен быть того же класса, что и ограничение, или производным от ограничения.For the type argument to satisfy a base class constraint, it must be the same class as the constraint or derive from the constraint.

Можно также ввести gcnew(), чтобы указать, что аргумент типа должен иметь открытый конструктор без параметров, ref class, чтобы указать, что аргумент типа должен быть ссылочным типом, включая любой тип класса, интерфейса, делегата или массива, или value class, чтобы указать, что аргумент типа должен быть типом значения.You can also specify gcnew() to indicate the type argument must have a public parameterless constructor; or ref class to indicate the type argument must be a reference type, including any class, interface, delegate, or array type; or value class to indicate the type argument must be a value type. Можно указать любой тип значения <T> , кроме Nullable.Any value type except Nullable<T> can be specified.

В качестве ограничения можно также указать универсальный параметр.You can also specify a generic parameter as a constraint. Аргумент типа, указанный для ограничиваемого типа, должен иметь тип ограничения или наследоваться о него.The type argument supplied for the type you are constraining must be or derive from the type of the constraint. Это называется открытым ограничением типа.This is called a naked type constraint.

КомментарииRemarks

Предложение ограничения состоит из ключевого слова where, за которым следуют параметр типа, двоеточие (:) и ограничение, определяющее характер ограничения параметра типа.The constraint clause consists of where followed by a type parameter, a colon (:), and the constraint, which specifies the nature of the restriction on the type parameter. where — контекстно-зависимое ключевое слово. Подробные сведения см. в статье Context-Sensitive Keywords (C++/CLI and C++/CX) (Контекстно-зависимые ключевые слова (C++/CLI and C++/CX)).where is a context-sensitive keyword; see Context-Sensitive Keywords for more information. Несколько предложений where следует разделять пробелом.Separate multiple where clauses with a space.

Ограничения применяются к параметрам типа для задания ограничений на типы, которые могут использоваться в качестве аргументов для универсальных типов и методов.Constraints are applied to type parameters to place limitations on the types that can be used as arguments for a generic type or method.

Ограничения класса и интерфейса определяют, что типы аргументов должны быть указанного класса или унаследованы от него либо должны реализовывать указанный интерфейс.Class and interface constraints specify that the argument types must be or inherit from a specified class or implement a specified interface.

Применение ограничений к универсальному типу или методу позволяет коду в этом типе или методе использовать известные возможности ограниченных типов.The application of constraints to a generic type or method allows code in that type or method to take advantage of the known features of the constrained types. Например, можно объявить универсальный класс так, чтобы параметр типа реализовывал интерфейс IComparable<T>:For example, you can declare a generic class such that the type parameter implements the IComparable<T> interface:

// generics_constraints_1.cpp
// compile with: /c /clr
using namespace System;
generic <typename T>
where T : IComparable<T>
ref class List {};

Это ограничение требует, чтобы аргумент типа, используемый для T, реализовывал IComparable<T> во время компиляции.This constraint requires that a type argument used for T implements IComparable<T> at compile time. Оно также позволяет вызывать методы интерфейса, например CompareTo.It also allows interface methods, such as CompareTo, to be called. Для вызова методов интерфейса приведение типа в экземпляре параметра типа не требуется.No cast is needed on an instance of the type parameter to call interface methods.

Вызывать статические методы в классе аргумента типа с помощью параметра типа нельзя. Их можно вызывать только с использованием фактического имени типа.Static methods in the type argument's class cannot be called through the type parameter; they can be called only through the actual named type.

Ограничение не может быть типом значения, включая встроенные типы, такие как int или double .A constraint cannot be a value type, including built-in types such as int or double. Поскольку типы значений не могут иметь производные классы, ограничению может удовлетворять только один класс.Since value types cannot have derived classes, only one class would ever be able to satisfy the constraint. В этом случае универсальный шаблон можно переписать с заменой параметра типа определенным типом значения.In that case, the generic can be rewritten with the type parameter replaced by the specific value type.

Ограничения требуются в некоторых случаях, поскольку компилятор не допускает использование методов и других функций неизвестного типа, если ограничениями не определено, что неизвестный тип поддерживает методы или интерфейсы.Constraints are required in some cases since the compiler will not allow the use of methods or other features of an unknown type unless the constraints imply that the unknown type supports the methods or interfaces.

Для одного параметра типа можно определить несколько ограничений в списке, разделенном запятыми.Multiple constraints for the same type parameter can be specified in a comma-separated list

// 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.With multiple type parameters, use one where clause for each type parameter. Пример:For example:

// 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 {};

Ограничения в коде следует использовать в соответствии с указанными ниже правилами.To summarize, use constraints in your code according to the following rules:

  • Ограничения можно перечислять в любом порядке.If multiple constraints are listed, the constraints may be listed in any order.

  • Ограничения также могут быть типами классов, например абстрактными базовыми классами.Constraints can also be class types, such as abstract base classes. Однако они не могут быть типами значений и запечатанными классами.However, constraints cannot be value types or sealed classes.

  • Ограничения сами не могут быть параметрами типа, но могут содержать параметры типа в открытом сконструированном типе.Constraints cannot themselves be type parameters, but they can involve the type parameters in an open constructed type. Пример:For example:

    // 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{};
    

ПримерыExamples

В следующем примере демонстрируется использование ограничений для вызова экземплярных методов для параметров типа.The following example demonstrates using constraints to call instance methods on type parameters.

// 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

Если в качестве ограничения используется параметр универсального типа, такое ограничение называется открытым ограничением типа.When a generic type parameter is used as a constraint, it is called a naked type constraint. Открытые ограничения типа применимы, когда функция-член со своим параметром типа должна ограничивать этот параметр параметром содержащего типа.Naked type constraints are useful when a member function with its own type parameter needs to constrain that parameter to the type parameter of the containing type.

В приведенном ниже примере T — открытое ограничение типа в контексте метода Add.In the following example, T is a naked type constraint in the context of the Add method.

Открытые ограничения типа также можно использовать в определениях универсальных классов.Naked type constraints can also be used in generic class definitions. Применение открытых ограничений типа с универсальными классами ограничено, поскольку в отношении таких ограничений компилятор может предполагать только то, что они являются производными от Object.The usefulness of naked type constraints with generic classes is limited because the compiler can assume nothing about a naked type constraint except that it derives from Object. Открытые ограничения типа следует использовать в универсальных классах в тех случаях, когда необходимо обеспечить отношение наследования между двумя параметрами типа.Use naked type constraints on generic classes in scenarios in which you wish to enforce an inheritance relationship between two type parameters.

// 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 {};

См. также разделSee also

Универсальные шаблоныGenerics