Здравствуйте, Baiker, Вы писали:
B>Это "объяснение" никак не объясняет, почему тогда виден P2!
Он не "виден", он — часть инициализатора.
Вы же заметили, что в object initializer нельзя слева написать произвольное lvalue? А только свойства инициализируемого объекта?
B>Кроме того, OI — это вам не "скобочки для if" — это специфическая часть, которая работает (у MS) только после new.
Всё верно. И она работает предсказуемым, понятным, и устойчивым к мелким изменениям образом.
B>А накой ляд тогда делать вообще OI, если он такой кривой???
Для упрощения инициализации объектов с большим количеством свойств, лишь малая часть которых нужна в каждом конкретном случае. Ваш К.О.
B>Вопрос-уточнение: мне не интересно, что думал Хлипперт и как конкретно он реализовал эту багофичу. С инженерной точки зрения что мешает видеть P1 и P?
То, что это принесёт больше вреда, чем пользы.
B>Наверное, может надо ПОДУМАТЬ и реализовать?
Может быть. Пока что видно, что ПОДУМАТЬ не желаете как раз вы.
Я сейчас не могу спонталыку просто взять и углубиться в тему компиляторостроения, но если вы приведёте пример такого вот "не очень понятно", то можно поговорить хотя бы о часностях.
B>Опережающий ответ:
B>1. Никто не сказал, что можно будет делать вложенные иниты.
И как вы собираетесь их запретить? На всякий случай поясню, что Object Initializer — это expression. И его, естественно, можно поставить
в любое место, где нужен expression.
То есть примерно везде — включая объемлющий object initializer.
B>В конце концов, 99.999999% кода — это как раз простые донельзя конструкции одного уровня.
Основная ценность object initializer — как раз конструирование сложных деревьев объектов. Если у вас простая линейная конструкция, то вам не нужен никакой object initializer — просто напишите цепочку присваиваний свойств.
B>2. Если они будут вложенные и как-то конфликтовать, ВСЕГДА можно посидеть и придумать какое-то интересное решение.
Проблема не в том, чтобы придумать решение. А в том, чтобы это решение не приводило к трудноуловимым багам и WTF. В том числе и в corner cases.
Вот вам простой пример. Версия кода 1:
public class Foo
{
public string DisplayName {get;set;}
public int Number {get; init;}
public Foo(int number)
{
Number = number;
DisplayName = number.ToString();
}
}
public class Bar
{
public string Name {get; init;}
public List<Foo> Foos {get; } = new();
public Bar(int seed) => Name = $"Bar #{new Random(seed).Next()}";
}
public class Program
{
public static void Main()
{
var b = new Bar(42) {
Foos = {
new Foo(1) { DisplayName = Name + ":" + Number},
new Foo(2) { DisplayName = Name + ":" + Number}
}
};
}
}
вроде всё хорошо, да? Name берётся из "текущего" Bar, Number — из "текущего" Foo.
Теперь автор класса Foo, который ничего не знает о коде Main (и, может быть, даже о коде Bar) публикует версию 2, добавляя невинно выглядящее свойство:
public class Foo
{
public string Name {get;set;}
public string DisplayName {get;set;}
public int Number {get; init;}
public Foo(int number)
{
Number = number;
Name = number.ToString();
DisplayName = number.ToString();
}
}
Автор Main забирает апдейт, компилирует. Всё успешно. Когда он получит баг репорт, он долго пытается понять, почему хорошо отлаженный код вдруг стал выдавать какую-то ересь.
Но вопрос даже не в этом — ну, допустим, он понял, в чём дело. Что ему теперь делать? Как вы предлагаете ему писать код Main так, чтобы он работал как в предыдущем случае?
B>Главное — БАЗОВАЯ ЛОГИКА должна быть инженерная, а не "у нас тут индусокод и вот так исторически сложилось".
Совершенно верно. Базовая логика как раз инженерная.
B>В конце концов, для чего вообще придумывать фичи, кроме как для УДОБСТВА ПРОГРАММИСТА? И на поверку оказалось, что OI-сахарок — чёрте что и полностью обламывает прямую логику разработчика.
Обламывает он только лично вас — и то потому, что вы вместо изучения инструмента придумываете неудачные варианты того, как он
мог бы (а точнее — не мог бы) работать.