Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Несвязанные универсальные типы в
Примечание.
Эта статья является спецификацией компонентов. Спецификация служит проектным документом для функции. Этот документ включает предлагаемые изменения спецификации, а также информацию, необходимую во время проектирования и разработки функции. Эти статьи публикуются до тех пор, пока предложенные изменения спецификации не будут завершены и включены в текущую спецификацию ECMA.
Может возникнуть некоторое несоответствие между спецификацией компонентов и завершенной реализацией. Эти различия отражены в соответствующих заметках с заседания по дизайну языка (LDM) .
Дополнительные сведения о процессе внедрения спецификаций функций в стандарт языка C# см. в статье о спецификациях .
Проблема чемпиона: https://github.com/dotnet/csharplang/issues/8662
Сводка
Позволяет использовать несвязанные универсальные типы с nameof
, как и в nameof(List<>)
, чтобы получить строку "List"
, а не указывать неиспользуемый аргумент универсального типа, чтобы получить ту же строку.
Мотивация
Это небольшая функция, которая удаляет общее разочарование: "Почему я должен выбрать аргумент универсального типа, когда выбор не влияет на оценку выражения?" Это очень странно, чтобы требовать, чтобы что-то было указано в операнде, когда он не оказывает влияния на результат. В частности, typeof
не страдает от этого ограничения.
Это также не просто о краткости и простоте. После выбора какого-то аргумента произвольного типа в выражении nameof
, например object?
, изменение ограничения параметра типа может прерывать использование nameof
ненужным образом. Оскорбление усугубляет травму в этой ситуации. Для удовлетворения параметра типа иногда может потребоваться объявление фиктивного класса, чтобы реализовать интерфейс, ограничивающий параметр типа. Теперь есть неиспользуемые метаданные и необычное имя, созданные для добавления аргумента типа в выражение nameof
. Этот аргумент типа nameof
в конечном итоге игнорирует, хотя и требует его.
В некоторых редких случаях с ограничением универсального класса даже невозможно использовать nameof
, потому что невозможно наследовать от базового класса, который используется в качестве универсального ограничения, из-за наличия внутреннего конструктора или внутреннего абстрактного члена.
Простое изменение позволяет достичь этого в языке с минимальной сложностью реализации в компиляторе.
Описание
Имена несвязанных типов становятся доступными для использования с nameof
:
-
nameof(A<>)
оценивается как"A"
-
nameof(Dictionary<,>)
оценивается как"Dictionary"
Кроме того, к цепочкам членов можно будет получить доступ на несвязанных типах, так же как и на связанных типах.
class A<T>
{
public List<T> B { get; }
}
-
nameof(A<>.B)
оценивается как"B"
-
nameof(A<>.B.Count)
оценивается как"Count"
Доступ к даже членам параметров универсального типа можно получить в соответствии с тем, как nameof
уже работает, если тип не является несвязанным. Так как тип неограничен, нет сведений о типах этих членов кроме того, что предоставляет System.Object
или какие-либо дополнительные общие ограничения.
class A<TItem, TCollection> where TCollection : IReadOnlyCollection<TItem>
{
public TCollection B { get; }
}
-
nameof(A<,>.B)
оценивается как"B"
-
nameof(A<,>.B.Count)
равен"Count"
.
Не поддерживается
Поддержка не предусмотрена для включения несвязанного типа в качестве аргумента к другому обобщенному типу, например
A<B<>>
илиA<B<>>.C.D
. Несмотря на то, что это может быть логически реализовано, такие выражения не имеют прецедента на языке, и нет достаточной мотивации для его введения:A<B<>>
не предоставляет никаких преимуществ по сравнению сA<>
, иA<B<>>.C
не предоставляет никаких преимуществ по сравнению сA<>.C
.Если
C
возвращаетT
A<T>
,A<B<>>.C.D
можно записать напрямую какB<>.D
. Если он возвращает другой тип,A<B<>>.C.D
не предоставляет никаких преимуществ по сравнению сA<>.C.D
.typeof()
имеет те же ограничения.
Поддержка не включается для частично несвязанных типов, таких как
Dictionary<int,>
. Аналогичным образом, такие выражения не имеют прецедента на языке, и нет достаточной мотивации. Эта форма не дает никаких преимуществ по сравнению сDictionary<,>
, а доступ к возвращаемым членамT
можно записывать проще без упаковки в частично связанный тип.
Подробный дизайн
Изменения грамматики
nameof_expression
: 'nameof' '(' named_entity ')'
;
named_entity
- : named_entity_target ('.' identifier type_argument_list?)*
+ : named_entity_target ('.' identifier (type_argument_list | generic_dimension_specifier)?)*
;
named_entity_target
: simple_name
| 'this'
| 'base'
| predefined_type
| qualified_alias_member
;
simple_name
- : identifier type_argument_list?
+ : identifier (type_argument_list | generic_dimension_specifier)?
;
generic_dimension_specifier
: '<' ','* '>'
Теперь это позволяет считать имена, такие как X<>
или X<,>
простыми именами, тогда как ранее они поддерживались только как unbound_type_name
в выражении typeof
.
Семантические изменения
Это ошибка использования generic_dimension_specifier
за пределами выражения typeof
или nameof
. В любом из этих выражений является ошибкой использование generic_dimension_specifier
в type_argument_list
, array_type
, pointer_type
или nullable_type
. Другими словами, все незаконные:
// Illegal, not inside `nameof` or `typeof`
var v = SomeType<>.StaticMember;
// All illegal
var v = typeof(List<>[]);
var v = typeof(List<>*);
var v = typeof((List<> a, int b));
Примечание. Приведённые выше правила эффективно служат для того, чтобы generic_dimension_specifier
не появлялся в пределах другого типа. Тем не менее, на высшем уровне, где разрешено использование спецификатора, можно свободно комбинировать с обычными type_argument_list
. Например, следующие варианты являются допустимыми:
var v = (nameof(X<>.Y<int>));
var v = (nameof(X<int>.Y<>));
Поиск элементов в выражении несвязанного типа в nameof
будет выполняться так же, как и для выражения this
в объявлении этого типа (за исключением выполнения проверок доступности в месте вызова). Другими словами, поиск на основе List<>
в nameof(List<>...)
работает так же, как и поиск на основе this
внутри типа class List<T>
.
Изменения не требуются для случаев, перечисленных в разделе Не поддерживается. Они уже предоставляют те же ошибки для выражений nameof
, что и для typeof
.
Изменение не требуется, если синтаксис nameof
привязывается к методу с именем «nameof», а не является контекстным ключевым словом nameof
. Передача любого выражения типа методу приводит к "CS0119: "..." — это тип, недопустимый в заданном контексте". Это уже охватывает несвязанные выражения универсального типа.
C# feature specifications