Комментарии 24
А какой смысл в SetsRequiredMembers если компилятор сам может эту проверку выполнить?
Кстати да, тоже непонятно. Но думается мне, что это для того чтобы убедится что поле точно инициализируется в хоть каком-то конструкторе. Сначала required объявили и если нет инициализации - "хоть тушкой, хоть чучелком" выкатываем ошибку. А [SetsRequiredMembers] явно указывает, что тут мы "сейчас будем играть во все игры". Раньше можно было warning'ами это отследить ("is null here") а теперь можно как ошибку засетапить. Наверное будет хорошо в REST запросах и так далее. А то там вечно бардак с параметрами...
Ну в принципе да, просто перевод говно. Если компилятор не смог вывести факт инициализации то его можно зафорсить этим аттрибутом.
Хм… "Если компилятор не смог вывести факт инициализации то его можно зафорсить этим аттрибутом". Разве это не означает, что компилятор не смог вывести факт инициализации без атрибута, но атрибут явно указывает (заставляет компилятор увидеть), что члены есть и всё-таки "выводит факт их инициализации". То есть задаёт члены, задать которые было необходимо, а раньше он их вообще не видел. Во всяком случае, уточнили, спасибо.
В языке C# уже есть понятие Definite Assignment, к которому все привыкли. Можно было бы его переиспользовать для свойств.
для типов налэбл, когда не ясно налейбл это установка или налэбл это присвоение
Очевидно для случая когда тип, конструктор которого вызываем, уже скомпилирован и находится в сторонней библиотеке
Очевидно что не для этого, выше уже разобрались что к чему. При вызове эта аннотация не нужна.
Если класс Person (из статьи) объявлен в отдельной сборке, как компилятор поймёт без атрибута на конструкторе, что
new Person();
запрещена, а
new Person("John", "Smith");
разрешена?
Декомпилировать код конструктора и смотреть, что он заполняет, а что нет?
required
.Автор библиотеки сможет пометить так конструктор и свойства, и компилятор будет знать что при вызове этого конструктора можно не требовать задания свойств, а этого - нужно. При этом к содержимому конструктора доступа у него нет.
По идеи компилятор этого класса сам мог бы пометить такие конструкторы данным свойством, чтобы вызывающий код знал, что конструкторы исчерпывающие
Нафига атрибут-то? Некоторые типовые (встроенные) атрибуты при компиляции исчезают - делается ли пометка флагом в специальных таблицах метаданных. То есть да - смысла в атрибуте после компиляции нет - в рефлексии он светиться не обязан (наоборот - только засорять всё будет). Напрямую на работу скомпилированных алгоритмов он не влияет. Нужна только спец пометка для компилятора при вызове такого кода. Да и то не 100% обязательная к выполнению (это уже на совести компилятора).
Кстати, может такая пометка и делается - и в рефлексии данного атрибута нет - надо будет проверить
Даже то что в с# коде не атрибуты зачастую является атрибутами в il. См. например learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute?view=net-6.0 или learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.extensionattribute?view=net-6.0 или даже learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.statemachineattribute?view=net-6.0
Кроме того, с# не единственный язык в .net экосистеме, и в эти языки далеко не всегда добавляют фичи из с#, а общаться друг с другом они должны. И делают это через атрибуты.
Ну в любом случае - это всё может делать исходный компилятор - не вынуждая программиста к явной пометке - а уже что в итоге будет в метаданных - спецфлаг или сгенерированный атрибут - не важно! Программиста напрямую это никак не должно касаться, и должно происходить в стороне, фоном.
Про "OptionalAttribute" не понял. В C# как раз не требуется помечать необязательные параметры методов этим атрибутом. Если Вы про то, что компилятор поставит его автоматически в метаданных у таки параметров - то ну и пусть - программиста то это делать не требуют. Вот и с обсуждаемой темой обязательных свойств и конструкторов полностью их инициализирующих - тут компилятор мог бы сам их поставить!
А вообще, я полностью на стороне атрибутов - со времён их первого появления в C# я просто влюбился в их идеологию. Жаль только, что
В C# так мало они задействованы в типовых конструкциях - считаю, что нужно было поменьше вводить зарезервированных слов - и побольше встроенных атрибутов - сейчас зарезервированных слов наплодили просто немерено и изрядно усложнив язык и компиляторы/анализаторы. Вот то же ключевое слово "required" вполне можно было бы заменить атрибутом [Required]. Вот только синтаксис атрибутов не особо удачный (но и не самый плохой) - луше было бы так &Required или как аннотации в Java @Required - но амперсанд мне нравится больше, а собачка используется уже во множестве других языков. А вот ключевые слова доступности я бы вынес в атрибуты. И чтобы можно было связывать атрибуты в одну строку - как то так: &Required&Public&Static&Virtual void method.
А если бы атрибуты ещё и по желанию можно было бы размещать справа от определения, а ещё и типы тоже.... эх.... это уже не C#.... увы даже и не совсем Kotlin - это уже оффтопик, за что прошу прощения.До Roslyn было мало толку в пользовательских атрибутах - их можно было анализировать только в рантайм через рефлексию - что снижало их популярность из-за снижения производительности (и даже runtime emit был не поноцеей - и при этом очень сложной технологией)! Но с приходом компилятора Roslyn, а за ним и системы когенерации (привет VS2022 и .NET 6 и .NET 7 - но можно и без них) и ряда библиотек таких как CodeAnalysis - ситуация изменилась в куда лучшую сторону - теперь на пользовательских атрибутах можно воротить невероятно продвинутый статически полиморфный код. И это надо активно пропагандировать. Вот тут как раз избыточные атрибуты могут оказаться очень полезны - это поможет кастомным анализаторам в анализе кода.
А частичное решение, эвристическое (если конструктор простой и точно инициализирует эти поля, то ставим метаданные, иначе не ставим) сильно перегрузит стандарт языка подробным описанием правил. Тем более, они могут развиваться.
А кто это за звери — «операторы вызова»?
Предварительная версия C# 11: обощённые типы для ML, обязательные члены и многое другое