После неудачной попытки скомпилировать что-то вроде следующего:
public class Gen<T> where T : System.Array
{
}
с ошибкой
Ограничение не может быть специальным классом System.Array.
Я начал задаваться вопросом , что именно это «особый класс»?
Кажется, что люди часто получают такую же ошибку, когда задают System.Enum
общее ограничение. Я получил те же результаты , с System.Object
, System.Delegate
, System.MulticastDelegate
и System.ValueType
тоже.
Их больше? Я не могу найти никакой информации о "специальных классах" в C #.
Кроме того , что это так особенного тех классов , которые мы не можем использовать их в качестве универсального типа ограничения?
c#
class
generics
generic-constraints
Mints97
источник
источник
System.Object
это не «особый класс», поскольку это действительно:,public class X : System.Object { }
ноSystem.Object
все же «особый класс».Ответы:
Из исходного кода Roslyn это выглядит как список жестко запрограммированных типов:
Источник: Binder_Constraints.cs IsValidConstraintType
Я нашел его с помощью поиска GitHub: «Ограничение не может быть специальным классом»
источник
CS0702
.object
), или, по крайней мере, это как-то связано с этим. Такжеwhere T : Array
позволит передать Assay как T, что, вероятно, не то, чего хочет большинство людей.Я нашел комментарий Джона Скита от 2008 года по аналогичному вопросу: почему
System.Enum
ограничение не поддерживается.Я знаю, что это немного не по теме , но он спросил об этом Эрика Липперта (команда C #), и они дали такой ответ:
источник
Согласно MSDN это статический список классов:
Ошибка компилятора CS0702
Ограничение не может быть идентификатором специального класса. Следующие типы не могут использоваться в качестве ограничений:
источник
System.MulticastDelegate
в списке?В соответствии со Спецификацией языка C # 4.0 (Закодировано: [10.1.5] Ограничения параметров типа) говорится о двух вещах:
Когда вы определяете универсальный класс, вы можете применять ограничения к типам типов, которые клиентский код может использовать для аргументов типа при создании экземпляра вашего класса. Если клиентский код пытается создать экземпляр вашего класса, используя тип, который не разрешен ограничением, результатом будет ошибка времени компиляции. Эти ограничения называются ограничениями. Ограничения указываются с помощью контекстного ключевого слова where. Если вы хотите ограничить универсальный тип ссылочным типом, используйте: class.
Это запретит универсальному типу быть типом значения, таким как int или struct и т. Д.
Кроме того, ограничение не может быть идентификатором специального класса. Следующие типы не могут использоваться в качестве ограничений:
источник
В Framework есть определенные классы, которые эффективно передают особые характеристики всем производным от них типам, но сами не обладают этими характеристиками. . Сама среда CLR не налагает запрета на использование этих классов в качестве ограничений, но связанные с ними универсальные типы не будут приобретать ненаследуемые характеристики, как конкретные типы. Создатели C # решили, что, поскольку такое поведение может сбить с толку некоторых людей, и они не видели в нем какой-либо полезности, им следует запретить такие ограничения, а не позволить им вести себя так, как они делают в среде CLR.
Если, например, разрешено писать
void CopyArray<T>(T dest, T source, int start, int count)
:; можно было бы передатьdest
иsource
методам, которые ожидают аргумент типаSystem.Array
; кроме того, можно было бы получить проверку во время компиляции, которыеdest
иsource
были совместимыми типами массивов, но нельзя было бы получить доступ к элементам массива с помощью[]
оператора.Невозможность использования
Array
в качестве ограничения в большинстве случаев довольно легко обойти, посколькуvoid CopyArray<T>(T[] dest, T[] source, int start, int count)
будет работать почти во всех ситуациях, когда будет работать первый метод. Однако у него есть слабость: первый метод будет работать в сценарии, в котором один или оба аргумента имеют тип,System.Array
при этом отклоняются случаи, когда аргументы являются несовместимыми типами массивов; добавление перегрузки, в которой оба аргумента имеют типSystem.Array
, заставит код принимать дополнительные случаи, которые он должен принимать, но также заставит его ошибочно принимать случаи, которые он не должен принимать.Я считаю решение объявить вне закона большинство специальных ограничений утомительным. Единственным, у которого было бы нулевое семантическое значение, было бы
System.Object
[поскольку, если бы это было законным как ограничение, ему удовлетворяло бы что угодно].System.ValueType
вероятно, было бы не очень полезно, поскольку ссылки типа наValueType
самом деле не имеют много общего с типами значений, но они могут иметь какое-то значение в случаях, связанных с отражением. ОбаSystem.Enum
иSystem.Delegate
будут иметь какое-то реальное применение, но поскольку создатели C # не думали о них, они объявлены вне закона без уважительной причины.источник
Следующее можно найти в CLR через C # 4th Edition:
Основные ограничения
Параметр типа может указывать ноль основных ограничений или одно основное ограничение. Первичное ограничение может быть ссылочным типом, который идентифицирует незапечатанный класс. Вы не можете указать один из следующих специальных типов ссылок: System.Object , System.Array , System.Delegate , System.MulticastDelegate , System.ValueType , System.Enum или System.Void . При указании ограничения ссылочного типа вы обещаете компилятору, что указанный аргумент типа будет либо одного типа, либо типа, производного от типа ограничения.
источник
System.Array
,System.Delegate
,System.MulticastDelegate
,System.Enum
, илиSystem.ValueType
. Более того, объявление универсального класса нельзя использоватьSystem.Attribute
как прямой или косвенный базовый класс.Я не думаю, что существует какое-то официальное определение «особых классов» / «особых типов».
Вы можете думать о них как о типах, которые нельзя использовать с семантикой «обычных» типов:
PS Добавлю
System.Void
в список.источник
System.Void
дает совершенно другую ошибку при использовании в качестве общего ограничения =)void
очень особенном. :)System.Array
может использовать такие методы, какArray.Copy
перемещение данных от одного к другому; код с параметрами ограниченного типаSystem.Delegate
сможет использоватьDelegate.Combine
их и привести результат к правильному типу . Эффективное использование общего известного типаEnum
будет использовать Reflection один раз для каждого такого типа, но универсальныйHasAnyFlag
метод может быть в 10 раз быстрее, чем неуниверсальный метод.