### Соблюдайте последовательность ключевых слов Последовательность ключевых слов после Where имеет значение: class или struct или unmanaged должны быть указаны в первую очередь, затем идут базовые классы или интерфейсы, и в конце new(). <br> ### Какие ключевые слова можно использовать в Where ##### class Ограничивает тип, указывая, что он должен быть ссылочным типом. ##### struct Ограничивает тип, указывая, что он должен быть значимым типом. ##### new() Ограничивает тип, указывая, что он должен иметь открытый конструктор без параметров. ##### unmanaged Ограничивает тип, указывая, что он должен быть неуправляемым типом. Неуправляемые типы в C# - это типы, которые могут быть представлены непосредственно в памяти, без дополнительной обработки сборщиком мусора (GC) и CLR (Common Language Runtime). Это обычно примитивные типы, такие как int, float, char и bool, а также структуры, которые содержат только неуправляемые типы. Ограничение unmanaged было добавлено в C# 7.3. Пример использования: ```csharp public void DoSomething<T>(T value) where T : unmanaged { //... } ``` ##### Имя базового класса Ограничивает тип, указывая, что он должен быть производным от указанного базового класса. ##### Имя интерфейса Ограничивает тип, указывая, что он должен реализовывать указанный интерфейс. ##### T Используется для наложения ограничений на второй или последующий параметры типа, что указывает, что они должны быть производными от первого параметра типа. ```csharp public class Pair<T, U> where U : T { // ... } ``` Здесь U обязано быть подтипом T, т.е. оно должно быть либо тем же самым типом, либо типом, производным от T. Это ограничение дает вам уверенность, что вы можете безопасно использовать экземпляр U там, где ожидается T. <br> <br> ### Если в where указано через запятую несколько типов, то что это значит? Если в where указано несколько типов через запятую, это означает, что тип, переданный в качестве параметра обобщения, должен соответствовать всем указанным ограничениям. Вот пример использования нескольких ограничений: ```csharp public class MyGenericClass<T> where T : class, IComparable<T>, new() { // ... } ``` В этом примере T должен быть ссылочным типом (так как указано class), должен реализовывать интерфейс IComparable\<T> и должен иметь открытый конструктор без параметров (так как указано new()). <br> <br> <br> ### Можно ли в where указать условие "или"? Контекст: ```csharp public bool IsOrderCompleted <TSubscribeC, TObservableC>() where TSubscribeC : SubscribeComponent, new() where TObservableC : OrderComponent ``` <br> Нет, нельзя. (Также погуглил, тоже не нашел такой возможности) Альтернативой может быть - это использовать интерфейсы для определения общего поведения и затем применить ограничение на интерфейс. Пример: ```csharp public interface ICommonComponent { } public class SubscribeComponent : ICommonComponent { } public class OrderComponent : ICommonComponent { } public class OtherComponent : ICommonComponent { } public bool IsOrderCompleted<TCommonComponent>() where TCommonComponent : ICommonComponent, new() { // Ваш код здесь } ``` <br> Теперь вы можете вызывать этот метод с разными типами, реализующими интерфейс ICommonComponent: ```csharp bool result1 = IsOrderCompleted<SubscribeComponent>(); bool result2 = IsOrderCompleted<OrderComponent>(); bool result3 = IsOrderCompleted<OtherComponent>(); ``` Если вы хотите ограничить метод только двумя конкретными типами (например, SubscribeComponent или OrderComponent), вы можете использовать перегрузку метода: ```csharp public bool IsOrderCompleted<TSubscribeC>() where TSubscribeC : SubscribeComponent, new() { // Ваш код здесь } public bool IsOrderCompleted<TObservableC>() where TObservableC : Order { // Ваш код здесь } ``` ChatGPT-4