Поделиться через


Устранение ошибок и предупреждений, связанных с параметрами универсального типа и аргументами универсального типа

В этой статье рассматриваются следующие ошибки компилятора:

  • CS0080: Ограничения не допускаются для необобщённых деклараций.
  • CS0081: объявление параметров типа должно быть идентификатором, а не типом.
  • CS0224: метод с vararg не может быть универсальным, быть в универсальном типе или иметь параметр params.
  • CS0304: не удается создать экземпляр типа переменной, так как он не имеет new() ограничения.
  • CS0305: для использования универсального типа требуются аргументы типа N.
  • CS0306: тип не может использоваться в качестве аргумента типа.
  • CS0307: идентификатор не является универсальным методом. Если вы планировали список выражений, используйте круглые скобки вокруг выражения.
  • CS0308: Необобщённый тип или метод нельзя использовать с аргументами типа.
  • CS0310: тип должен быть не абстрактным типом с открытым конструктором без параметров, чтобы использовать его в качестве параметра в универсальном типе или методе.
  • CS0311: тип нельзя использовать в качестве параметра T типа в универсальном типе или методе. Неявное преобразование ссылок из типа1 в тип2 отсутствует.
  • CS0312: Тип "type1" не может использоваться в качестве параметра типа в обобщённом типе или методе. Тип "type1", допускающий значение NULL, не удовлетворяет ограничению.
  • CS0313: Тип "type1" нельзя использовать в качестве параметра типа в универсальном типе или методе. Тип "type1", допускающий значение NULL, не соответствует ограничению. Типы, допускающие значение NULL, не могут удовлетворять ограничениям интерфейса.
  • CS0314: Этот тип нельзя использовать в качестве параметра типа в обобщенном типе или методе. Преобразование упаковки или преобразование параметра типа невозможно.
  • CS0315: тип нельзя использовать в качестве параметра T типа в обобщённом типе или методе. Нет преобразования упаковки.
  • CS0401: new() ограничение должно быть последним ограничением.
  • CS0403: не удается преобразовать значение NULL в параметр типа, так как это может быть ненулевой тип значения. Вместо этого рекомендуется использовать default(T) .
  • CS0405: повторяющееся ограничение для параметра типа.
  • CS0412: параметр: параметр, локальная переменная или локальная функция не могут иметь то же имя, что и параметр типа метода.
  • CS0413: параметр типа нельзя использовать с as оператором, так как он не имеет ограничения типа класса или class ограничения.
  • CS0417: идентификатор: не может предоставлять аргументы при создании экземпляра переменной типа.
  • CS0449: Ограничения class, struct, unmanaged, notnull и default не могут быть объединены или дублированы и должны быть сначала указаны в списке ограничений.
  • CS0450: параметр type: не может указывать как класс ограничений, так и classstruct ограничение.
  • CS0451: new() ограничение нельзя использовать с ограничением struct.
  • CS0454: зависимость с циклическим ограничением, включающая параметр типа 1 и параметр типа 2.
  • CS0455: параметр type наследует конфликтующие ограничения.
  • CS0694: параметр type имеет то же имя, что и содержащий тип или метод.
  • CS0695: T не может реализовать оба интерфейса, так как они могут объединиться для некоторых подстановок параметров типа.
  • CS0698: универсальный тип не может быть производным от типа, так как это класс атрибутов.
  • CS0702: ограничение не может быть специальным классом.
  • CS0703: Несогласованная доступность: тип ограничения менее доступен, чем объявление.
  • CS0706: недопустимый тип ограничения. Тип, используемый в качестве ограничения, должен быть интерфейсом, непечатанным классом или параметром типа.
  • CS0717: статический класс: статические классы нельзя использовать в качестве ограничений.
  • CS1961: недопустимая дисперсия: параметр типа должен быть допустимым вариантом для типа.
  • CS7002: неожиданное использование универсального имени.
  • CS8322: не удается передать аргумент с динамическим типом в универсальную локальную функцию с аргументами выводимых типов.
  • CS9011: Ключевое слово delegate нельзя использовать в качестве ограничения. Вы имели в виду System.Delegate?
  • CS9012: Неожиданное ключевое слово record. Вы имели в виду record struct или record class?
  • CS9338: Несоответствующая доступность: тип менее доступен, чем класс.

Объявление и именование параметров типа

Следующие ошибки связаны с объявлением и именованием параметров типа в универсальных типах и методах.

  • CS0080: ограничения не допускаются для не универсальных объявлений.
  • CS0081: объявление параметров типа должно быть идентификатором, а не типом.
  • CS0412: параметр: параметр, локальная переменная или локальная функция не могут иметь то же имя, что и параметр типа метода.
  • CS0694: параметр type имеет то же имя, что и содержащий тип или метод.
  • CS9012: неожиданное ключевое слово record. Вы имели в виду record struct или record class?

Чтобы исправить эти ошибки, убедитесь, что вы объявляете параметры типа с допустимыми идентификаторами, применяйте предложения ограничений только к универсальным объявлениям и избегайте конфликтов именования с другими идентификаторами в области:

  • Удалите условие ограничения из необобщённых объявлений (CS0080). Предложение where может использоваться только для универсальных типов и методов, объявляющих параметры типа, так как ограничения определяют требования, которые должны удовлетворять аргументы типа. Если необходимо применить ограничения, сначала добавьте параметры типа в объявление типа или метода. Например, измените public class MyClass where MyClass : System.IDisposable на public class MyClass<T> where T : System.IDisposable.
  • Замените фактические имена типов идентификаторами в объявлениях параметров типа (CS0081). Необходимо объявить параметры типа с помощью идентификаторов (например T, TKeyили TValue) вместо конкретных типов (например int , или string). Назначение параметра типа — служить заполнителем, который компилятор заменяет фактическими типами при использовании универсального типа или метода. Например, измените public void F<int>() на public void F<T>().
  • Переименуйте параметры типа, локальные переменные или параметры, чтобы избежать конфликтов именования (CS0412, CS0694). Имена параметров типа не могут заслонять идентификаторы в той же области видимости. Они не могут соответствовать имени содержащего типа или метода. Такие конфликты создают неоднозначность о том, на какой идентификатор ссылается. Например, если у вас есть метод public void F<T>(), вы не можете объявить локальную переменную double T внутри этого метода, и нельзя назвать параметр типа так же, как и его содержащий тип (class C<C>).
  • Используйте правильный синтаксис объявления записей (CS9012). При объявлении типа записи необходимо использовать record class или record struct (или только record для ссылочного типа). Ключевое слово record не может использоваться в позициях, в которых компилятор ожидает синтаксис объявления типов. Например, если вы хотите объявить тип записи, напишите record class MyRecord или record struct MyRecord вместо размещения record там, где ожидается другое ключевое слово.

Дополнительные сведения см. в разделе "Параметры универсального типа " и "Универсальные типы".

Объявление ограничений и порядок

Следующие ошибки связаны с синтаксисом и упорядочением ограничений для параметров универсального типа:

  • CS0401: new() ограничение должно быть последним ограничением.
  • CS0449: Ограничения class, struct, unmanaged, notnull и default не могут быть объединены или дублированы и должны быть указаны первыми в списке ограничений.
  • CS0450: параметр type: не может указывать как класс ограничений, так и classstruct ограничение.
  • CS0451: Ограничение new() нельзя использовать с ограничением struct.
  • CS9011: ключевое слово delegate нельзя использовать в качестве ограничения. Вы имели в виду System.Delegate?

Ограничения параметров типа должны соответствовать определенному порядку: первичные ограничения (class,, structunmanaged, notnullилиdefault) приходят первым, а затем ограничения интерфейса или класса и, наконец, ограничение конструктораnew(). Некоторые ограничения являются взаимоисключающими и не могут быть объединены.

Чтобы исправить эти ошибки, выполните указанные ниже действия.

  • Поместите new() ограничение в конец списка ограничений (CS0401). Ограничение new() должно отображаться после всех других ограничений. Например, измените where T : new(), IDisposable на where T : IDisposable, new().
  • Сначала поместите основные ограничения и не сочетайте взаимоисключающие ограничения (CS0449). В списке ограничений можно указать не более одного из class, struct, unmanaged, notnull или default, и он должен появиться первым. Ограничения class являются взаимоисключающими, как и structclass.unmanaged В nullable контексте class уже подразумевает notnull, поэтому их нельзя объединить.
  • Не сочетайте определенное ограничение класса с struct (CS0450). Если параметр типа ограничен определенным типом класса, это неявно ссылочный тип, который противоречит ограничению struct . Удалите ограничение класса или struct ограничение.
  • Не сочетайте new() с struct (CS0451). Все типы значений (структуры) неявно имеют открытый конструктор без параметров, поэтому new() ограничение избыточно при сочетании с struct. Удалите ограничение new() при использовании struct.
  • Замените delegate на System.Delegate в предложениях ограничений (CS9011). Ключевое delegate слово используется для объявления типов делегатов, а не в качестве ограничения. Чтобы ограничить параметр типа делегированным типам, используйте System.Delegate в качестве типа ограничения. Например, измените where T : delegate на where T : System.Delegate.

В следующем примере показано правильное упорядочение ограничений:

using System;

// Primary constraint first, then interface constraints, then new()
class C<T> where T : class, IDisposable, new() { }

// struct doesn't need new() - it's implicit
class D<T> where T : struct, IComparable { }

// Delegate constraint using System.Delegate
class E<T> where T : System.Delegate { }

Дополнительные сведения см. в статье Ограничения параметров типа.

Количество аргументов типа и использование

Следующие ошибки связаны с предоставлением правильного числа и типа аргументов типа универсальным типам и методам:

  • CS0224: метод с vararg не может быть универсальным, быть в универсальном типе или иметь параметр params.
  • CS0305: для использования универсального типа требуются аргументы типа N.
  • CS0306: тип не может использоваться в качестве аргумента типа.
  • CS0307: идентификатор не является универсальным методом. Если вы планировали список выражений, используйте круглые скобки вокруг выражения.
  • CS0308: Не являющийся универсальным тип или метод нельзя использовать с аргументами типа.
  • CS7002: неожиданное использование универсального имени.

Чтобы исправить эти ошибки, убедитесь, что укажите точное количество аргументов типа, необходимых универсальному объявлению. Используйте только допустимые типы в качестве аргументов типа. Не применяйте аргументы типа к не универсальным конструкциям:

  • Удалите параметры универсального типа или содержащие объявления универсальных типов из методов, использующих __arglist (CS0224). Ключевое __arglist слово несовместимо с универсальными шаблонами, так как механизмы среды выполнения для обработки списков аргументов переменной конфликтуют с подстановкой типов, необходимой для параметров универсального типа. Это ограничение также применяется к ключевому слову params при его использовании с универсальными методами или методами в универсальных типах.
  • Укажите точное число аргументов типа, указанных в объявлении универсального типа или метода (CS0305). Каждый параметр универсального типа, объявленный в определении, должен иметь соответствующий аргумент типа при создании экземпляра универсального типа. Компилятор должен знать, какой конкретный тип следует заменить для каждого параметра типа. Например, если класс объявлен как class MyList<T>, необходимо указать ровно один аргумент типа при его использовании, например MyList<int>, не MyList<int, string>.
  • Используйте только допустимые типы в качестве аргументов типа (CS0306). Типы указателей, такие как int* или char*, нельзя использовать в качестве аргументов типов, поскольку универсальные типы требуют управляемых типов, которые сборщик мусора может отслеживать, а типы указателей являются неуправляемыми. Если вам нужно работать с указателями в универсальном контексте, рассмотрите возможность использования IntPtr или реструктуризации кода, чтобы избежать смешивания универсальных элементов с небезопасным кодом.
  • Удалите синтаксис аргумента типа из не универсальных конструкций (CS0307, CS0308). Аргументы типа, заключенные в угловые скобки (например <int>), могут применяться только к универсальным типам и методам, объявляющим параметры типа. Необходимо полностью удалить аргументы типа или убедиться, что вы импортировали пространство имен, содержащее универсальную версию типа. Например, IEnumerator<T> требует директиву using System.Collections.Generic;, тогда как IEnumerator находится в System.Collections.
  • Удалите параметры типа из объявлений, которые не поддерживают обобщения (CS7002). Некоторые конструкции, такие как перечисления, не могут быть обобщёнными. Если вам нужен универсальный контейнер для перечисляемых значений, рассмотрите возможность использования универсального класса или структуры.

Дополнительные сведения см. в разделе "Параметры универсального типа " и "Универсальные типы".

Ограничения конструктора

Следующие ошибки связаны с ограничением new() параметров универсального типа:

  • CS0304: не удается создать экземпляр типа переменной, так как он не имеет new() ограничения.
  • CS0310: тип должен быть не абстрактным типом с открытым конструктором без параметров, чтобы использовать его в качестве параметра в универсальном типе или методе.
  • CS0417: идентификатор: не может предоставлять аргументы при создании экземпляра переменной типа.

Чтобы исправить эти ошибки, добавьте new() ограничение к параметрам типа, которые необходимо создать, убедитесь, что аргументы типа имеют открытые конструкторы без параметров и не передают аргументы при создании экземпляров параметров типа:

  • Добавьте ограничение new() к объявлению параметра типа (CS0304). При использовании new оператора для создания экземпляра параметра типа в универсальном типе или методе компилятор должен гарантировать, что любой аргумент типа, предоставленный во время выполнения, имеет доступный конструктор без параметров. Ограничение new() обеспечивает эту гарантию во время компиляции, позволяя компилятору создавать соответствующий код экземпляра. Например, если у вас есть class C<T> с элементом T t = new T();, необходимо изменить объявление на class C<T> where T : new().
  • Убедитесь, что аргументы типа, используемые с new() параметрами ограниченного типа, имеют публичные конструкторы без параметров (CS0310). Если универсальный тип или метод объявляет new() ограничение для параметра типа, любой конкретный тип, используемый в качестве аргумента типа, должен быть не абстрактным и должен предоставлять открытый конструктор без параметров. Если тип имеет только недоступные конструкторы (например private , protected конструкторы) или только конструкторы с параметрами, он не может удовлетворить new() ограничение. Чтобы устранить эту ошибку, добавьте в тип открытый конструктор без параметров или используйте другой аргумент типа, который уже имеет один.
  • Удалите аргументы конструктора при инициализации типовых параметров (CS0417). Ограничение new() гарантирует только существование конструктора без параметров, поэтому невозможно передать аргументыnew T(arguments), так как компилятор не может проверить наличие конструктора с указанными типами параметров в типах, заменяемых.T Если необходимо создать экземпляры с определенными аргументами, рассмотрите возможность использования фабричных методов, абстрактных фабричных шаблонов или определенных ограничений базового класса или интерфейса, которые определяют требуемое поведение при построении.

Для получения дополнительной информации см. раздел «Ограничения для параметров типов» и new() ограничение.

Удовлетворение ограничений и преобразования

Следующие ошибки связаны с аргументами типа, не удовлетворяющими ограничениям параметров универсального типа:

  • CS0311: Этот тип нельзя использовать в качестве параметра T в универсальном типе или методе. Отсутствует неявное преобразование ссылок.
  • CS0312: тип нельзя использовать в качестве параметра типа в универсальном типе или методе. Тип, допускающий значение NULL, не удовлетворяет ограничению.
  • CS0313: тип нельзя использовать в качестве параметра типа в универсальном типе или методе. Тип, допускающий значение NULL, не удовлетворяет ограничению. Типы, допускающие значение NULL, не могут удовлетворять ограничениям интерфейса.
  • CS0314: тип нельзя использовать в качестве параметра типа в универсальном типе или методе. Преобразование в бокс или преобразование параметров типа отсутствует.
  • CS0315: Тип нельзя использовать в качестве параметра T типа в обобщенном типе или методе TypeorMethod<T>. Преобразования упаковки нет.

Чтобы исправить эти ошибки, используйте аргументы типа, удовлетворяющие всем ограничениям с помощью соответствующих преобразований, убедитесь, что производные классы повторяют ограничения базового класса и понимают, что типы значений, допускающие значение NULL, имеют особые требования к ограничению:

  • Измените аргумент типа на тот, который имеет неявное преобразование ссылок на тип ограничения (CS0311). Если параметр типа имеет ограничение, например where T : BaseType, то любой аргумент типа должен быть преобразуем в BaseType через неявное преобразование ссылок или тождественное преобразование. Аргумент типа должен быть BaseType, производным от BaseType или реализовать BaseType, если BaseType является интерфейсом. Неявные числовые преобразования (например, от до shortint) не удовлетворяют ограничениям параметров универсального типа, так как эти преобразования являются преобразованиями значений, а не ссылочными преобразованиями.
  • Повторите ограничения параметров типа базового класса в любом объявлении производного класса (CS0314). Если производный универсальный класс наследует от базового универсального класса, имеющего ограничения на его параметры типа, производный класс должен объявить те же ограничения для соответствующих параметров типа. Необходимо повторить эти ограничения, так как компилятору необходимо проверить, что аргументы типа, предоставленные производному классу, удовлетворяют требованиям базового класса. Например, если у вас есть public class A<T> where T : SomeClass, то любой класс, производный от него, должен быть объявлен как public class B<T> : A<T> where T : SomeClass.
  • Используйте типы значений, не допускающие значение NULL, или измените тип ограничения (CS0312, CS0313). Типы значений, допускающие значение NULL (например int?, отличаются от их базовых типов значений и не удовлетворяют тем же ограничениям). Между int? и int нет неявного преобразования, а типы значений, допускающие NULL, не могут удовлетворить ограничения интерфейса, потому что оболочка NULL не реализует интерфейс, хотя базовый тип значения реализует его. Чтобы устранить эти ошибки, используйте ненулевую форму типа значения в качестве аргумента типа или измените ограничение, чтобы принимать object или тип nullable ссылки, если это подходит.
  • Убедитесь, что аргументы типов удовлетворяют ограничениям ссылочного типа или класса (CS0315). Если параметр типа ограничен типом класса (например where T : SomeClass, вы не можете использовать тип значения (структуру) в качестве аргумента типа, так как преобразование бокса не удовлетворяет связи ограничений. Для ограничения требуется ссылочный тип, который имеет отношение наследования или реализации с типом самого ограничения. Чтобы устранить эту ошибку, измените структуру на класс, если это семантически оправдано, или удалите ограничение класса, если универсальный тип может работать с типами-значениями.

Дополнительные сведения см. в разделе "Ограничения" для параметров типа и неявных преобразований.

Ограничения использования универсального типа

Следующие ошибки связаны с ограничениями на использование универсальных типов:

  • CS0403: не удается преобразовать значение NULL в параметр типа, так как это может быть ненулевой тип значения. Вместо этого рекомендуется использовать default(T) .
  • CS0413: параметр типа нельзя использовать с as оператором, так как он не имеет ограничения типа класса или class ограничения.
  • CS0695: Тип не может реализовать оба интерфейса, поскольку они могут быть объединены для некоторых подстановок параметров типа.
  • CS0698: универсальный тип не может быть производным от типа, так как это класс атрибутов.
  • CS8322: не удается передать аргумент с динамическим типом в универсальную локальную функцию с аргументами выводимых типов.
  • CS9338: Несоответствующая доступность: тип менее доступен, чем класс.

Чтобы исправить эти ошибки, используйте default вместо null параметров без ограничений типа, добавьте ограничения классов при использовании as оператора, избегайте конфликтов объединения интерфейса, не создавайте универсальные классы атрибутов и убедитесь, что аргументы типов соответствуют видимости их содержащих членов:

  • Замените присваивания null на default(T) или добавьте ограничение class (CS0403). При назначении null параметру без ограничений компилятор не может гарантировать, что аргумент типа является ссылочным типом, принимаюющим null значения, так как это может быть тип значения, например int или struct, который не может быть null. Чтобы устранить эту ошибку, используйте default(T), который предоставляет подходящее значение по умолчанию для любого типа (null для ссылочных типов, ноль или пустая строка для типов значений) или добавьте ограничение class к параметру типа, если требуется семантика ссылочного типа и хотите позволить назначения null.
  • Добавьте class или конкретное ограничение типа при использовании as оператора (CS0413). Оператор as выполняет безопасное приведение типа, результатом которого является null, если преобразование завершается ошибкой, но это поведение несовместимо с типами значений, поскольку они не могут быть null. При использовании as с параметром без ограничений компилятор не может гарантировать, что аргумент типа не является типом значения, поэтому он отклоняет код. Чтобы устранить эту ошибку, добавьте ограничение class или конкретное ограничение для ссылочного типа (например, where T : SomeClass), чтобы гарантировать, что параметр типа всегда является ссылочным типом, который может правильно обрабатывать результат неудачного приведения null.
  • Избегайте реализации одного и того же универсального интерфейса несколько раз с параметрами типа, которые могут быть объединены (CS0695). Когда класс реализует универсальный интерфейс несколько раз с разными параметрами типа (например class G<T1, T2> : I<T1>, I<T2>), существует риск, что кто-то может создать экземпляр класса с одинаковым типом для обоих параметров (G<int, int>), что приведет к конфликту, поскольку класс будет реализовывать I<int> дважды. Чтобы устранить эту ошибку, реализуйте интерфейс только один раз, переструктурируйте параметры типа, чтобы предотвратить объединение, или использовать отдельные не универсальные классы для разных специализаций.
  • Удалите параметры универсального типа из классов атрибутов (CS0698).

    Замечание

    Эта ошибка не создается в текущих версиях C#, так как теперь поддерживаются универсальные атрибуты.

  • Явно укажите аргументы типа при передаче динамических значений универсальным локальным функциям (CS8322). При передаче аргумента dynamic в универсальную локальную функцию компилятор не может выводить аргументы типа, так как фактический тип не известен до выполнения. Чтобы устранить эту ошибку, явно укажите аргумент типа (например, LocalFunc<int>(d)), приведите динамическое значение к ожидаемому типу или используйте нединамическую переменную.
  • Убедитесь, что аргументы типа, используемые в общедоступных или защищенных сигнатурах, по крайней мере, так же доступны, как и член, который их использует (CS9338). Общедоступный или защищенный универсальный член должен использовать аргументы типа, которые являются общедоступными. В противном случае внешний код не мог правильно ссылаться или использовать подпись члена. Например, если у вас есть `public class Container<T>`, где `T` является внутренним типом, внешние сборки могут видеть `Container`, но не могут правильно с ним работать, потому что они не могут видеть `T`. Чтобы устранить эту ошибку, сделайте аргумент типа общедоступным или уменьшите специальные возможности члена, используя его для сопоставления специальных возможностей аргумента типа.

Дополнительные сведения см. в разделе "Ограничения" для параметров типа, выражений значений по умолчанию и атрибутов.

Допустимые типы ограничений

Следующие ошибки связаны с использованием недопустимых типов в качестве ограничений для параметров универсального типа:

  • CS0405: повторяющееся ограничение для параметра типа.
  • CS0702: ограничение не может быть специальным классом.
  • CS0703: Несогласованная доступность: тип ограничения менее доступен, чем объявление.
  • CS0706: недопустимый тип ограничения. Тип, используемый в качестве ограничения, должен быть интерфейсом, непечатанным классом или параметром типа.
  • CS0717: static classстатические классы нельзя использовать в качестве ограничений.

Ограничение должно быть интерфейсом, непечатанным классом или параметром типа. Некоторые типы недопустимы в качестве ограничений из-за их специального значения в системе типов .NET или из-за того, что они не могут быть унаследованы.

Чтобы исправить эти ошибки, выполните указанные ниже действия.

  • Удалите повторяющиеся ограничения (CS0405). Каждое ограничение может отображаться только один раз в предложении ограничения. Если у вас есть where T : I, I, удалите дубликат.
  • Не используйте специальные классы в качестве ограничений (CS0702). Типы Objectи ArrayValueType не могут использоваться в качестве ограничений. Каждый тип уже является производным от Object, поэтому ограничение для него не предоставляет никакого значения. Array и ValueType являются абстрактными базовыми типами, которые нельзя наследовать напрямую. Если требуется поведение массива, используйте IList<T> или IEnumerable<T> вместо этого.
  • Убедитесь, что типы ограничений не менее доступны, чем универсальный тип (CS0703). Общедоступный универсальный тип не может иметь ограничений с использованием внутренних типов, так как внешний код не сможет предоставлять допустимые аргументы типа. Либо сделать тип ограничения общедоступным, либо уменьшить доступность универсального типа.
  • Используйте только интерфейсы, непечатанные классы или параметры типа в качестве ограничений (CS0706). Нельзя использовать массивы, запечатанные классы, структуры, перечисления или другие недопустимые типы в качестве ограничений. Если требуется определенное поведение, рассмотрите возможность использования интерфейса, реализуемого требуемыми типами.
  • Не используйте статические классы в качестве ограничений (CS0717). Статические классы нельзя расширить, так как они содержат только статические элементы. Тип не может существовать, производный от статического класса, что делает его бесполезным в качестве ограничения. Вместо этого используйте нестатический класс или интерфейс.

В следующем примере показаны допустимые типы ограничений:

public interface IMyInterface { }
public class MyBaseClass { }

// Valid: interface constraint
class A<T> where T : IMyInterface { }

// Valid: non-sealed class constraint
class B<T> where T : MyBaseClass { }

// Valid: type parameter constraint
class C<T, U> where T : U { }

Дополнительные сведения см. в статье Ограничения параметров типа.

Конфликты ограничений и циклические зависимости

Следующие ошибки связаны с конфликтами между ограничениями или циклическими зависимостями в объявлениях ограничений:

  • CS0454: зависимость с циклическим ограничением, включающая параметр типа 1 и параметр типа 2.
  • CS0455: параметр type наследует конфликтующие ограничения.

Ограничения не могут создавать циклические зависимости, а параметры типа не могут наследовать конфликтующие ограничения, которые невозможно удовлетворить одновременно.

Чтобы исправить эти ошибки, выполните указанные ниже действия.

  • Удалите зависимости кругового ограничения (CS0454). Параметр типа не может напрямую или косвенно зависеть от себя с помощью ограничений. Например, where T : U where U : T создает циклическую зависимость, так как T зависит от U, а U зависит от T. Разорвать цикл, удалив одно из ограничений.
  • Удалите конфликтующие наследуемые ограничения (CS0455). Параметр типа не может быть ограничен несколькими несвязанными классами, так как C# не поддерживает наследование нескольких классов. Аналогично, его нельзя ограничить одновременно как struct, так и типом класса, поскольку эти ограничения взаимоисключают друг друга. Переструктурируйте иерархию типов или удалите одно из конфликтующих ограничений.

В следующем примере показаны проблемы:

// CS0454: Circular dependency - T depends on U and U depends on T
class Circular<T, U> where T : U where U : T { }

// CS0455: Conflicting constraints - U can't derive from both B and B2
public class B { }
public class B2 { }
public class G<T> where T : B
{
    public class N<U> where U : B2, T { }
}

Дополнительные сведения см. в статье Ограничения параметров типа.

Вариантность параметров типа

Следующая ошибка связана с модификаторами дисперсии для параметров универсального типа:

  • CS1961: недопустимая дисперсия: параметр типа должен быть допустимым вариантом для типа.

Модификаторы вариации (in для контравариации, out для ковариации) управляют использованием параметров типа в объявлениях интерфейса и делегатов. Параметр типа ковариантного (out) может отображаться только в выходных позициях (возвращаемых типах), а параметр типа контравариантного (in) может отображаться только в входных позициях (типах параметров).

Чтобы исправить эту ошибку, выполните указанные ниже действия.

  • Используйте out (ковариант) для параметров типа, которые отображаются только в возвращаемых типах. Ковариация позволяет использовать более производный тип, где ожидается менее производный тип.
  • Используйте in (contravariant) для параметров типа, которые отображаются только в типах параметров. Контравариантность позволяет использовать менее производный тип, где ожидается более производный тип.
  • Удалите модификатор дисперсии, если параметр типа должен отображаться как в входных, так и в выходных позициях.

В следующем примере показано правильное и неправильное использование дисперсии:

// Incorrect: out T can't appear in input position
interface IWrong<out T>
{
    void Method(T arg);  // CS1961
}

// Correct: out T only in output positions
interface ICovariant<out T>
{
    T GetValue();
}

// Correct: in T only in input positions
interface IContravariant<in T>
{
    void Process(T arg);
}

// No modifier needed for both input and output
interface IInvariant<T>
{
    T Transform(T arg);
}

Дополнительные сведения см. в разделе «Ковариация и контравариантность в универсальных шаблонах».