Именно, что «так», я описал конкретное условие (не единственное). Константы должны идти раньше покрывающего их типа...
В вашей изначальной формулировке вы упустили важное уточнение «покрывающего их типа», поскольку в общем случае типы и константы могут и не перекрывать друг друга.
А теперь давайте вспомним, что проверки на константы должны идти раньше проверок на типы, а null — это тоже константа. И где тут логика?
А что касается null, то никакой тип не может его перекрыть.
Как вы думаете, что будет, если написать так:
Мы надуем наш умный компилятор! :)
(очень поучительно посмотреть на релизный код при switch(6) и switch(5))
Ничего удивительного, компилятор удаляет недостижимые ветви кода.
Неа. В примере введено несколько временных однобуквеных переменных, которые надо отслеживать обратно к месту создания.
Для меня имя переменной не влияет на явность. Да, оно может влиять на читаемость кода, но не на явность. Если вы посмотрите декомпиляцию, то увидите, что инициализационные блоки тоже используют временные локальные переменные аналогичные To-With, разница лишь в том, что в первом случае эта переменная вводится компилятором неявно и к ней нельзя получить доступ из пользовательского кода, а во втором мы сами её явно объявляем и используем.
Затем же, зачем и With паттерн, потому что инициализационный блок — это всего лишь его частный случай с неявной переменной, чуть более лаконичным синтаксисом, но более ограниченными возможностями.
У вас у коллекции нет конструктора с множеством элементов? Сочувствую.
Да? Как насчёт
ReadCollectionFromFile().To(out var c)
.With(c.Name = "abc")
.Merge(item1, item2, GetItem3(), item4)...
Просто. Не. Делайте. Так. Дерево должно быть гарантированно внутренне консистентным, поэтому присвоение родителя должно автоматически добавлять элемент в коллекцию детей и наоборот.
Я вам продемострровал принцип инициализации замкнутого графа, а как должно работать дерево — это уже конкретная задача, может, оно должно быть «неконсистентным» для каких-то нужд.
… что не имеет никакого отношения к замене конструктора на фабричный метод.
Имеет, фабричный метод вполне может инициализировать ссылочные переменные дефолтными инстенсами, если нужно.
Person CreatePerson() => new Person {
City = new City { Name = "unknown" }
};
И ещё такой момент — здесь много «корпоративной политики», ибо зачем блокировать в репозитории пользователя, который вовсе не нарушал правил поведения, а просто отстаивал альтернативную точку зрения? Тем более, если она настолько слабая и не выдерживает авторитетной критики…
А теперь давайте вспомним, что проверки на константы должны идти раньше проверок на типы, а null — это тоже константа. И где тут логика?
Не должны, C# допускает произвольный порядок проверок на типы и значения. Как их размещать, в зависимости от требуемой логики, дело разработчика.
Правда? То есть ваш прекрасный пример «а вот тут был дебаг» никому никогда не надо повторять для каждого шага в цепочке, которых бывает много?
Слабо понимаю вашу критику, но если вы примитивно копипастите код из одного места в другое, то конфликт имён может произойти, где угодно. Простите, но, скажу прямо, для меня такая проблема выглядит высасонной из пальца. Кроме того, вы не замечаете, как решаются конфликты другого рода, неразрешимые на текущий момент в терминах инициализационных блоков. Например,
new NamedCollection().To(out var c)
.With(c.Name = "abc")
.Merge(item1, item2, GetItem3(), item4)...
И весьма интересный сценарий с замыканием графа
var tree = new Node().To(out var r).With(
r.Child = new Node().To(out var c).With(
c.Root = r
)
);
Это той самой реструктуризации, которую современные IDE делают в один клик?
К сожалению, IDE не может понять, когда нужен p.City?.With(...), а когда p.City = new City...
Разная спецификация типа — это для вас минимально отличающаяся запись?
var для меня означает лишь вывод типа из контекста выражения, а не разную спецификацию. Тот факт, что на него навесили странную дополнительную логику, нарушив принципы разделения ответственности и грамотной композиции, лежит уже на совести архитекторов. Я просто не поддерживаю их решение, используя свои кастомные модификации с чистой интуитивной имплементацией.
Долго пытался выяснить объективные причины, зачем это было необходимо и почему не сделали более грамотно, но один из архитекторов языка (признав, что это хоть и болячка) мотивировал решение острой необходимостью данной конструкции в выражениях вида is {… } x и case {… } x и тем, что команда дизайна верит в это решение. К сожалению, на аргументированную критику и предложенный альтернативный и более функциональный Check-паттерн (аналог With) никто из команды мне больше не ответил.
Правда в произвольном? А если вам надо сравнить с еще одной константой?
Произвольном в контексте данного примера, если вы меняете пример, то порядок может иметь значение.
Современные IDE позволяют запросто переименовывать переменные, если нужно, а учитывая, что нацелено расширение на цепочные вызовы в expression bodied конструкциях, то вероятность возникновения коллизии имён с другими переменными минимальна.
Вот только они мне об этом скажут, когда я код уже скопировал и вставил. Я бы, знаете, предпочел такого избегать.
А я предпочту избежать гораздо более рутинной и неудобной реструктуризации кода при замене конструктора на метод-фабрику.
Так что ошибиться легко, достаточно два раза подряд объявить одну переменную.
Эм-м-м… Среда разработки и компилятор вам срузу об этом скажут, в C# два раза объявить переменную в одном контексте нельзя. Или я вас неправильно понял?
Ключевые слова async и await формально тоже не являются частью C#? Где границы этой формальности? Может, просто не стоит возводить формальность в культ, а прибегать к ней по мере надобности?
Деньги — это косвенный и комплексный фактор фактор. Можно быть богачём и спускать их на ветер, а можно быть середнячком и вкладывать в развитие и образование — эффект будет совершенно разный. А бывает, денег не хватает, даже чтобы оплатить школу…
Вы просто ответьте сами себе на такой вопрос. Представьте, что у вас есть ребёнок, проявляющий способности к чему либо… Вы можете пустить всё на самотёк и заниматься своими делами в удовольствие, а можете приложить некоторые усилия и способствовать развитию этих способностей у ребёнка, отдать его, например, на соответствующий кружок, поощерять прогресс, тратить ресурсы на это.
Конечно, здравый смысл и житейский опыт подсказывают, что второй вариант более благоприятный. Вы можете спорить до умопомрачения, что «здравый смысл» часто не работает, а «житейский опыт» обманывает, искать исследования на тему влияния детских кружков на мышление и прочее, и прочее… Но что это вам даёт? Уверенность? В чём?
А что касается null, то никакой тип не может его перекрыть.
Мы надуем наш умный компилятор! :)
Ничего удивительного, компилятор удаляет недостижимые ветви кода.
Нет, вы путаете. Это рабочий код
И по моей логике он должен быть абсолютно эквивалентен
Увы, текущая реализация в C# этому не соответствует.
Во-вторых, не знаю, как для вас, но для меня цепочные вызовы выглядят намного более структурировано и читаемо.
А я не против. )
Вообще-то в примере они описаны явно и прекрасно работают.
Так никогда не пробовали написать?
Я вам продемострровал принцип инициализации замкнутого графа, а как должно работать дерево — это уже конкретная задача, может, оно должно быть «неконсистентным» для каких-то нужд.
Имеет, фабричный метод вполне может инициализировать ссылочные переменные дефолтными инстенсами, если нужно.
И ещё такой момент — здесь много «корпоративной политики», ибо зачем блокировать в репозитории пользователя, который вовсе не нарушал правил поведения, а просто отстаивал альтернативную точку зрения? Тем более, если она настолько слабая и не выдерживает авторитетной критики…
Не должны, C# допускает произвольный порядок проверок на типы и значения. Как их размещать, в зависимости от требуемой логики, дело разработчика.
И весьма интересный сценарий с замыканием графа
К сожалению, IDE не может понять, когда нужен p.City?.With(...), а когда p.City = new City...
Долго пытался выяснить объективные причины, зачем это было необходимо и почему не сделали более грамотно, но один из архитекторов языка (признав, что это хоть и болячка) мотивировал решение острой необходимостью данной конструкции в выражениях вида is {… } x и case {… } x и тем, что команда дизайна верит в это решение. К сожалению, на аргументированную критику и предложенный альтернативный и более функциональный Check-паттерн (аналог With) никто из команды мне больше не ответил.
Произвольном в контексте данного примера, если вы меняете пример, то порядок может иметь значение.
А я предпочту избежать гораздо более рутинной и неудобной реструктуризации кода при замене конструктора на метод-фабрику.
На мой взгляд,
либо
существенно более интуитивно, благодаря ключевому слову default.
Для вас нет, а для меня это «грязный» синтаксис, которого я просто избегаю.
Наоборот удобно, если мне нужно по особому обрабатывать null, то пишу
Причём, кейсы можно размещать в произвольном порядке! А в другом случае
IMHO Покрасивше выглядит, чем unexpected case var.
Состояние определено после вызова Expose — остальное не имеет значения в данном контексте.
Вы просто ответьте сами себе на такой вопрос. Представьте, что у вас есть ребёнок, проявляющий способности к чему либо… Вы можете пустить всё на самотёк и заниматься своими делами в удовольствие, а можете приложить некоторые усилия и способствовать развитию этих способностей у ребёнка, отдать его, например, на соответствующий кружок, поощерять прогресс, тратить ресурсы на это.
Конечно, здравый смысл и житейский опыт подсказывают, что второй вариант более благоприятный. Вы можете спорить до умопомрачения, что «здравый смысл» часто не работает, а «житейский опыт» обманывает, искать исследования на тему влияния детских кружков на мышление и прочее, и прочее… Но что это вам даёт? Уверенность? В чём?