C#: required
Некоторые разработчики предпочитают объектную инициализацию использованию конструкторов. Кто-то негодует из-за вынужденного "перекладывания" аргументов из одного конструктора в другой при наследовании. Кому-то конструкторы не нравятся просто как таковые. Но возможна ли жизнь без конструкторов?
Если на скриншоте слева копипаст вам еще не кажется адским, представьте что аргументов у базового конструктора больше и MyClassChild тоже есть наследники, которые вынуждено наследуют родительский копипаст.
Object initialization
Простое решение здесь это банально не копипастить, отказаться от конструкторов, сделать сервисы паблик и создавать экземпляры через объектную инициализацию(в фигурных скобочках). Очевидной проблемой такого подхода является потеря каких-либо гарантий того, что мы точно проинициализировали все, что нужно. NullReference будет поджидать вас на каждой инициализации, ведь полное покрытие тестами обычно кажется слишком большой ценой.
Также становится сомнительно использование init в купе с nullable reference types. Дело в том, что мы теряем гарантии того, что init св-во не null:
Record
Records, представленные в C# 9 частично спасают ситуацию, но перекладывать аргументы все еще надо, плюс, не всегда хочется терять мутабельность:
Object initialization + Required
Нам поможет, на текущий момент proposed, фича - Required Members. Члены, обязательные для инициализации помечаются новым ключевым словом required, что дает возможность компилятору проверять, факт инициализации:
error CS9506: Required member 'MyClassNew.Service1' must be set in the object initializer or attribute constructor.
Модификатор допустим для полей и св-в классов, структур и рекордов. "Под капотом", члены типа с required
а также и сам тип помечаются атрибутом [RequiredMember]
. Как не сложно догадаться, есть вагон и маленькая тележка кейсов, в которых новый модификатор конфликтует с уже существующими. Из того, что на поверхности - такое поле нельзя делать недоступным для присвоения извне().
При этом конструкторы, не гарантирующие инициализацию всех required
членов типа, принудительно("под капотом") помечаются как нежелательные для использования. В том числе и конструктор по умолчанию:
Заключение
Как и прочие языковые фичи, required
должен применяться там, где он упрощает, а не усложняет жизнь, это не "золотая пуля". Лично я немного устал от бесполезных реализаций конструкторов, очень жду момента, когда их можно будет выпилить.