Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В универсальном определении используйте where предложение для указания ограничений типов, используемых в качестве аргументов для параметров типа в универсальном типе, методе, делегате или локальной функции. Можно указать интерфейсы, базовые классы или требовать, чтобы универсальный тип был ссылкой, значением или неуправляемным типом. Эти ограничения объявляют возможности, которые должен иметь аргумент типа.
where Поместите предложение после любого объявленного базового класса или реализованных интерфейсов.
Справочные документы по языку C# описывают последнюю выпущенную версию языка C#. Она также содержит начальную документацию по функциям в общедоступных предварительных версиях для предстоящего языкового выпуска.
Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.
Подсказка
Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей об истории версий языка C#.
Например, можно объявить универсальный класс AGenericClass так, чтобы параметр типа T реализовывал интерфейс IComparable<T>:
public class AGenericClass<T> where T : IComparable<T> { }
Примечание.
Дополнительные сведения о предложении where в выражении запроса см. в разделе Предложение where.
Предложение where также может включать ограничение базового класса. Ограничение базового класса указывает, что тип, используемый в качестве аргумента типа для этого универсального типа, имеет указанный класс в качестве базового класса или является базовым классом. Если вы используете ограничение базового класса, оно должно отображаться перед любыми другими ограничениями для этого параметра типа. Некоторые типы не могут использоваться как ограничение базового класса: Object, Array и ValueType. В следующем примере показаны типы, которые можно указать в качестве базового класса:
public class UsingEnum<T> where T : System.Enum { }
public class UsingDelegate<T> where T : System.Delegate { }
public class Multicaster<T> where T : System.MulticastDelegate { }
В контексте, допускаемом значение NULL, компилятор применяет значение NULL для типа базового класса. Если базовый класс не допускает значения NULL (например, Base), аргумент типа должен иметь значение, отличное от NULL. Если базовый класс имеет значение NULL (например Base?, аргумент типа может быть пустым или не допускаемым значением NULL ссылочного типа). Компилятор выдает предупреждение, если аргумент типа является ссылочным типом, допускающим значения NULL, когда базовый класс не допускает значения NULL.
Предложение where может указывать, что тип является class или struct. Ограничение struct избавляет от необходимости указывать ограничение базового класса System.ValueType. Тип System.ValueType нельзя использовать в качестве ограничения базового класса. Ограничения class и struct показаны в следующем примере:
class MyClass<T, U>
where T : class
where U : struct
{ }
В контексте, допускающем значение NULL, class ограничение требует, чтобы тип был ссылочным типом, не допускающим значение NULL. Чтобы разрешить ссылочные типы, допускающие значения NULL, используйте ограничение class?, которое разрешает ссылочные типы, допускающие и не допускающие значения NULL.
Предложение where может включать notnull ограничение. Ограничение notnull ограничивает параметр типа типами, допускающими значение NULL. Тип может быть типом значения или ссылочным типом, не допускаемым значением NULL. Ограничение notnull доступно для кода, скомпилированного в контекстеnullable enable. В отличие от других ограничений, если аргумент типа нарушает ограничение notnull, компилятор генерирует предупреждение вместо ошибки. Предупреждения генерируются только в контексте nullable enable.
Добавление ссылочных типов, допускающих значения NULL, приводит к возможной неоднозначности значения T? в универсальных методах. Если T имеет значение struct, то T? соответствует System.Nullable<T>. Но если T имеет ссылочный тип, для T? допустимо значение null. Так как переопределяющиеся методы не могут включать в себя ограничения, возникает неоднозначность. Новое ограничение default устраняет ее. Добавьте его, когда базовый класс или интерфейс объявляет две перегрузки метода, один из которых задает struct ограничение, и тот, который не имеет примененного struct или class ограничения:
public abstract class B
{
public void M<T>(T? item) where T : struct { }
public abstract void M<T>(T? item);
}
default Используйте ограничение, чтобы указать, что производный класс переопределяет метод без ограничения в производном классе или явной реализации интерфейса. Оно допустимо только для методов, переопределяющих базовые методы, или явных реализаций интерфейса:
public class D : B
{
// Without the "default" constraint, the compiler tries to override the first method in B
public override void M<T>(T? item) where T : default { }
}
Внимание
Вы можете использовать универсальные объявления, которые включают notnull ограничение в неизменяемый контекст null, но компилятор не применяет ограничение.
#nullable enable
class NotNullContainer<T>
where T : notnull
{
}
#nullable restore
Предложение where также может включать unmanaged ограничение. Ограничение unmanaged позволяет использовать в качестве параметра типа только типы, называемые неуправляемыми типами. Ограничение unmanaged упрощает написание кода взаимодействия низкого уровня на языке C#. Это ограничение включает подпрограммы с возможностью повторного использования для всех неуправляемых типов. Ограничение unmanaged нельзя использовать с ограничением class или struct. Ограничение unmanaged требует тип struct:
class UnManagedWrapper<T>
where T : unmanaged
{ }
Предложение where также может включать ограничение конструктора. new() Это ограничение позволяет создать экземпляр параметра типа с помощью new оператора.
Ограничение new() сообщает компилятору о том, что все предоставленные аргументы типа должны иметь доступный конструктор без параметров. Например:
public class MyGenericClass<T> where T : IComparable<T>, new()
{
// The following line is not possible without new() constraint:
T item = new T();
}
Ограничение new() отображается последним в where предложении, если за ним не следует allows ref struct анти-ограничение. Ограничение new() не может использоваться с ограничениями struct или unmanaged. Все типы, удовлетворяющие этим ограничениям, должны иметь доступ к конструктору без параметров, поэтому ограничение new() будет избыточным.
Это анти-ограничение объявляет, что аргумент T типа для может быть типом ref struct . Например:
public class GenericRefStruct<T> where T : allows ref struct
{
// Scoped is allowed because T might be a ref struct
public void M(scoped T parm)
{
}
}
Универсальный тип или метод должен соответствовать правилам безопасности ссылок для любого экземпляра T , так как это может быть ref struct. Предложение allows ref struct не может сочетаться с или class ограничениемclass?. Анти-ограничение allows ref struct должно соответствовать всем ограничениям для этого аргумента типа.
Если параметров типа несколько, для каждого из них необходимо использовать по одному предложению where, например:
public interface IMyInterface { }
namespace CodeExample
{
class Dictionary<TKey, TVal>
where TKey : IComparable<TKey>
where TVal : IMyInterface
{
public void Add(TKey key, TVal val) { }
}
}
Кроме того, ограничения можно присоединять к параметрам типа универсальных методов следующим образом:
public void MyMethod<T>(T t) where T : IMyInterface { }
Синтаксис, описывающий ограничения параметров типа для делегатов, совпадает с синтаксисом методов:
delegate T MyDelegate<T>() where T : new();
Дополнительные сведения об универсальных делегатах см. в разделе Универсальные делегаты.
Дополнительные сведения о синтаксисе и применении ограничений см. в разделе Ограничения параметров типа.
Спецификация языка C#
Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.