C# - pattern matching - many discards
Вопрос про оформление и красивости. И можно ли вообще так написать.
Вобщем, понадобилось проверить объект на кучку разномастных условий. Например, на налл весь объект, на значение одно из свойств, если объект не налл, и вернуть что-то другое, если какие-то ещё условия. И хочу спросить, как удобнее сделать, чтобы не писать простыную из вложенных ифов. Пусть мы получили где-то объект row кастомного типа и хотим сделать подобные проверки. Как вы находите такую запись - удобной, читаемой, или лучше пачку вложенных ифов?
var result = row switch { null => MyEnum.NotAllowed, _ when row.Age > 100 => MyEnum.Died, _ => MyEnum.StillAlive, };
Тут результат быдет перечислением MyEnum.
Насколько я знаю, все выражения в выражении свича проверяются по порядку написания до первого соответствия, так что первая проверка на налл всего объекта - нормально. Меня смутило только возможность сделать несколько дискардов, т.к. полный объект мне не нужен. Ну или может можно как-то без дискардов обойтись.
Я могу так переписать, но мне что-то первый вариант больше нравится - можно добавить проверок других свойств row, и тогда логично, что входной параметр свича это весь объект. Но в любом случае есть пачка дискардов - не смущает ли она?
var result = row.Age switch { _ when row == null => MyEnum.NotAllowed, > 100 => MyEnum.Died, _ => MyEnum.StillAlive, };
Альтернатива в ифах
MyEnum result; if (row != null) { if (row.Age > 100) { result = MyEnum.Died; } else { result = MyEnum.StillAlive; } } else { result = MyEnum.NotAllowed; }
Ситуация с ифами ухудшается, если количество проверок увеличивается. А в сопоставлениях с образцом - просто добавляется одна строчка на проверку.
Древовидная структура ифов легко трансформируется в линейную структуру сопоставлений, просто порядок соблюдать надо - сначала одну ветку ифов последовательно в сопоставлениях пишем, потом другую. Разве что если условий становится больше десятка, как и вложенностей - по 3-4 и больше. Но и тогда на мой взгляд сопоставления лучше - они хотя бы на экран влезут, а дерево ифов явно расползётся куда дальше. Ну и всегда можно отделить группы кейсов в сопоставлениях форматированием - добавить между ними пустую строчку, например. А в ифах уже и так места нет, так ещё их удлинять.
var result = row.Age switch { _ when row == null => MyEnum.NotAllowed, > 100 => MyEnum.Died, _ => MyEnum.StillAlive, };
Не уверен, но тут, по-моему, может NullReferenceException вылететь уже на row.Age, если row налл. Ну можно тогда так написать row?.Age.
var result
Вот 3 варианта получить "result" на чистом сишарповском языке. Результат везде одинаков.
Похоже мы опять изобретаем очередной велосипед.
Этих реализаций дофига, например
https://docs.fluentvalidation.net/en/latest/start.html
https://github.com/Blazored/FluentValidation
https://code-maze.com/complex-model-validation-in-blazor/
и свитч и ифы не подходят, если уж свое сильно хочется.
ну так написал же... Пишешь просто набор правил
RuleFor(x => x.Surname).NotEmpty(); RuleFor(x => x.Forename).NotEmpty().WithMessage("Please specify a first name"); RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount); RuleFor(x => x.Address).Length(20, 250); RuleFor(x => x.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
RuleFor(x => x.Name).NotEmpty().WithMessage("name cannot be null");
RuleFor(x => x.Phone).NotEmpty();
RuleFor(x => x.Other).GreaterThan(0).WithMessage("other must be great than 0");;
ну так написал же... Пишешь просто набор правил
Вы чтобы в туалет сходить, сначала строите маленький заводик по производству туалетной бумаги? А если понос? ))
Дискарды юзаю только потому, что в условиях должен быть тип входного для свича параметра.
Можно бы было произвольные условия проверки писать - обошёлся бы без этого костыля. Но произвольно в паттерн матчинг пока не завезли.
Во первых, всё уже написано,
во вторых, был вопрос как нравится
Вы не поняли - проверки могут быть где угодно, а не лишь внутри ваших безнес-правил. И там не обязательно объект с полями, а может быть просто скажем строка. Проверяем её на налл, длину, наличие такого или иного символа или их сочетания... Ну понятно, вы и тут правила свои напишете - в виде расширения класса строк. Любой лапшекод, лишь бы паттерн матчинг не использовать )))
Ситуация с ифами ухудшается, если количество проверок увеличивается. А в сопоставлениях с образцом - просто добавляется одна строчка на проверку.
Перепиши if так, чтобы была одна строчка на проверку.
MyEnum result; if (row == null) result = MyEnum.NotAllowed; else if (row.Age > 100) result = MyEnum.Died; else result = MyEnum.StillAlive;
Тоже можно. Но текста куда больше из-за засилья словесных операторов и присвоения в каждой строчке.
С другой стороны, в моём варианте используются ненужные мне дискарды в качестве костылей. В идеале должно быть [условие] => [возврат].
Вот красным отметил информационный мусор в моём и вашем вариантах
В идеале должно быть [условие] => [возврат].
------
Об этом мы спорили во времена Аксесс 2.
есть плюсы... есть и минусы...
Самый простой вопрос - у тебя два и более различаемых условий независящих от переменной в свитче - что писать будешь?
Чуть более сложный - что с производительностью при большом числе правил?
Самый простой вопрос - у тебя два и более различаемых условий независящих от переменной в свитче - что писать будешь?
Свободно можно использовать. Как я выше написал - сначала нужен костыль-значение с типом переменной, или дискард, а затем "when" и далее любые проверки с любыми переменными из контекста, в котором находится данный свитч. Разве что результат такой проверки должен быть булевым.
Про производительность не знаю. По-моему, раз все эти проверки условий (if-else, switch) взаимозаменяемы, то они генерятся в одинаковый исполняемый код. Их разные записи - лишь для удобства использования в разных случаях. А значит вопрос производительности того или другого высокоуровневого кода не стоит - стоит вопрос производительности итогового исполняемого кода. Ну, думаю, там какую-нибудь хеш-таблицу замутили на все обозначенные программистом комбинации условий, так что при проходе по ветке условий сразу нужная имплементация выполняется.
проверки могут быть где угодно
ну тогда и ничего обсуждать о подобной программе, делайте как нравится и будет счастливы.
Я бы еще посчитал, что нам потребуется для предыдущего кода во всех местах.
вы и тут правила свои напишете
единого решения для всех случаев жизни не существует
ну тогда и ничего обсуждать о подобной программе, делайте как нравится и будет счастливы.
Ну так я и спросил, как бы вы сделали в подобном случае. Просто обычно везде один дискард для всех необработанных кейсов используется, а у меня получается, что можно дискард как костыль использовать для кейсов, когда надо сравнить что-то не с самой переменной свича.
Не, это ещё больший костыль - объекты создавать лишь для сравнения с константой.
А этот паттерн с созданием нового объекта с проверкой при инициализации - он вообще трудночитаем. Без подробного пояснения, что там происходит, непонятно.
Дискард с условием when проще и понятнее.
дискард с when позволяет провести проверку, не привязанную к параметру свича.
Не совсем так... Извращаться можно по разному
int a = 2; MyEnum ret = row switch { { Age: > 100 } when a == 2 => MyEnum.Died, { Age: <= 100 } => MyEnum.StillAlive, _ => MyEnum.NotAllowed }
Скажем так - дискард с when позволяет провести проверку, не привязанную к параметру свича...
...и при этом иметь меньше мусора и извращений. Добавить не нужный мне здесь символ подчёркивания - меньшее из зол.
Добавить не нужный мне здесь символ подчёркивания
Это и есть очень большая проблема. discard pattern ... that doesn't have the corresponding member of the Direction
enumeration
https://learn.microsoft.com/en-us/dotnet/csharp/language-r...
То бишь, это то, что должно выполнятся когда ничего не совпадает. И енто обычно одно и только одно.
А тут к этому одному добавляется еще и условие (и может не одно). Очень ломает привычный паттерн использования. Вместо одного ожидаемого дискарда их фиг знает сколько и ради чего?
И енто обычно одно и только одно.
-------
хи-хи... Я его об этом уже спрашивал...
Решение, кстати, есть.Но! оно - медленное...
Я вроде отвечал - иногда охото сравнить разнотиповые значения, а вернуть - одого типа. Скажем, проверить одну переменную double на пачку диапазонов, и вторую строковую переменную - на пару значений. А вернуть что-то из enum, например. Или вот тут что непонятного - делаю проверку всего объекта на налл, затем свойства этого объекта - ещё как-то, и кейс для всех остальных вариантов? И делаю это не пачкой if-else, а в несколько компактных строчек. Усложнил свой первоначальный пример - сколько это расписывать деревом if-else?
var (result, message) = (row, flag) switch { (null, _) => (MyEnum.NotAllowed, null), (_, Flags.CantDie) when row.Age > 100 => (MyEnum.Immortal, LocalizedStrings.Immortal), (_, _) when row.Age > 100 => (MyEnum.Died, LocalizedStrings.Died), (_, _) => (MyEnum.StillAlive, LocalizedStrings.Alive), };
я чот не пойму, а что в этом варианте не по фен-шую?
Очень даже много
1. Проверяется всего лишь одно поле, жирно слишком будет, по свитчу на каждое поле.
2. Если Age будет нуллабле и мне нужно будет отличать варианты или объект null или возраст null (не указан), то приплыли.
3. Происходит инверсия понятий - дискард вешается на "нормальный" вариант. Можно конечно и так, но это тогда должно быть везде. И если еще какой-то отрицательный вариант был забыт, то получаем по умолчанию Ок, что не есть правильно.
Если вопрос про красивости, то такой код на код-ревью я бы не принял. Во-первых затраты на его понимание превышают пределы чтения тривиальной проверки на null и тернарного оператора ?:. Во-вторых, а соответствует ли он Kodierrichtlinien? В третих, такая нотация предполагает знание Linq в контексте SQL, что является избыточным для тривиального куска кода общего назначения. Короче, привнесена специфика туда, где она даром не нужна; не будет сходу всем понятна и на нее нужно тратить время. Но это ИМХО конечно же.
решение чего?
-------
Проблемы двух и более срабатывающих кэйсов в одном свитче.
А решение - последовательное вычисление каждого условия... и - да - результат начинает зависеть от положения селектора, но прикладники сказали что им пофиг...
Если у вас срабатывают более одного кейса, значит у вас должно быть больше кейсов - где-то вы не поделили один кейс на несколько. А я предложил то же решение, что и у вас, но вместо последовательного перечисления одного кейса за раз, а проверяю кейсы попарно, потройно и т.д. за счёт ключевого слова when. Это позволяет объединить проверки в группы по их логике. Плюс кортежи - ещё удобнее.
Производительность, кстати, должна быть почти одинакова. Просто ваши одиночные проверки, разделённые на два кейса, у меня будут двумя проверками в одном кейсе. Лишь в случае, если у вас подходит сразу первый кейс, то у вас будет быстрее. Но если мы не бьёмся за байтики и тактики, то читабельность и объединение кейсов по логике вещей важнее.
Во-первых затраты на его понимание превышают пределы чтения тривиальной проверки на null и тернарного оператора ?:.
Проверка на налл и этот ваш оператор могут максимум 4 кейса проверить. Кроме того, в вашем случае вы смешиваете разные операторы - сначала if-else (на налл), затем ?:. У меня всё проверено единообразно в 3-5 строчек, а не на треть экрана расписано. По сути у меня понятная и удобная таблица истинности, а не кучка разномастных операторов.
Во-вторых, а соответствует ли он Kodierrichtlinien?
Смотря какие linien. Но странно, если они будут запрещать использовать свичи и вообще всё новое из новых версий Дотнета, хотя проект именно на этих версиях написан. Зачем на новые версии переходить тогда? Последняя Виндовс поддерживает в том числе и старые версии Дотнета - старпёрь, не хочу.
В третих, такая нотация предполагает знание Linq в контексте SQL, что является избыточным для тривиального куска кода общего назначения. Короче, привнесена специфика туда, где она даром не нужна; не будет сходу всем понятна и на нее нужно тратить время. Но это ИМХО конечно же.
Линка там нет. А кто не знает язык - его проблемы. Может, мне на второй версии Дотнета писать, а то кто-то в 20-летней давности застрял? Объективно, у меня нет никаких ребусов, над которыми надо было бы ломать голову, а кортежи и свичи - это уже считайте азы.
Насчёт сходу всем понятна - те, кто изучают язык с последних версий, могут как раз не понять портянку if-else вместо удобной таблицы истинности, записанной свичом, постоянные проверки на налл через те же if-else вместо null propagation. Вобщем, всё относительно. Но идти на поводу у старпёров, которые дальше второй-третьей версии Дотнета и языка не ушли, нет смысла. Особенно, когда сам проект на одной из последних версий.
"Красивости" это только звучит "даром не нужно". Но если это позволяет записать код в 3 раза короче, умещая на один экран, то это делает его зачастую и понятнее, т.к. не надо скроллить туда-сюда, теряя контекст.
Ну я же упомянул ИМХО, не злитесь. Когда-то Страуструп сказал, что мы не может ориентироваться на невежество читателя в написании кода (что-то в этом духе), но к сожалению эти времена прошли. Сейчас времена аджайла, среднестатистического разработчика, спринты, тайм ту маркет и вообще приближение индустрии 4.0. Гении не нужны - "Не дядя Вова, скрипач не нужен"
Я думаю, мы в целом о разных вещах говорим. Если вы остаетесь в рамках некоей технической реализации, то ок, ваш код имеет место быть - ваше право и ваш креатив. Если же мы пытаемся его интегрировать, то нужно рассматривать другие аспекты, например, скажут ли вам спасибо все остальные читатели вашего кода в рамках вашего проекта. Ну и старперы, куда уж без них.
Свитч выражения введены в 8 версии Сишарпа в 2019 году, с первой версии Дотнет Коре. Зачем нам переходить на Коре, если мы сидим на скажем третьей версии (2006 год)?
Видел команды, которые пишут на WPF как на формах - не используя привязки, шаблоны, стили, словари ресурсов, команды - вобщем, ничего из MVVM. Просто фигачат в code-behind, вместо стилей повторяют все настройки представления для каждого элемента копипастингом, если они одинаковые. Крутые сеньёры, уже много лет поддерживающие крупный проект для крупных фирм. Походу, они и разметку не использовали, а лишь визуальный редактор форм - что генерилось в разметке, их не интересовало. Непонятно, зачем им нужен был WPF. И вот такие чудаки обкладываются всякими linien - сами нормально не пишут, и другим не дают.
Зачем нам переходить на Коре, если мы сидим на скажем третьей версии (2006 год)?
Кстати да, а зачем переходить? Какие-то есть обоснования к переходу? Мы закроем какие-то бизнес-кейсы? Или давайте просто потратим деньги?
Видел команды, которые пишут на WPF как на формах - не используя привязки, шаблоны, стили, словари ресурсов, команды - вобщем, ничего из MVVM
Легаси код. Интересный вопрос: нужен ли редизайн или мы остаемся консистентными? Как сами думаете?
сами нормально не пишут, и другим не дают
Вот жеж ... нехорошие люди. Как жить-то? Нужен манифест джунов, ибо им там не здесь, не посрамим и т.п. Вам самому не смешно?
Есть такое предположение, что она будет понятна и удобна исключительно автору
дожили блин.
теперь современным надо подстраиваться под людей с закостенелым мозгом.
потом мы удивляемся, почему в Германии не создаются никакие продуктов мирового масштаба.
Проверяется всего лишь одно поле, жирно слишком будет, по свитчу на каждое поле.
вообще пофиг. Если решение занимает вместо 15 строк всего 5, то я за
Если Age будет нуллабле и мне нужно будет отличать варианты или объект null или возраст null (не указан), то приплыли.
частично соглашусь, но поскольку в исходной версии возраст не проверялся на null, я предположил, что он примитивный.
Происходит инверсия понятий - дискард вешается на "нормальный" вариант.
в какой-то библии написано, что дискард обязательно должен обрабатывать нештатные ситуации? Рассматривай его как обычный else, не забивай себе голову.
Зачем нам переходить на Коре, если мы сидим на скажем третьей версии (2006 год)?Кстати да, а зачем переходить? Какие-то есть обоснования к переходу? Мы закроем какие-то бизнес-кейсы? Или давайте просто потратим деньги?
Если долго не переходить, то потом можно закрыть не бизнес кейсы, а бизнес вообще.
У нас тоже лет 15-20 не переходили, а потом МС поддержку IE зарубила, и пришлось всё приложение переписывать. Ну зато копеечки по постепенному и планомерному переходу экономили. А сейчас - срочно нужно вбухать много денег и в темпе вальса свинга переписать почти всё, а что не переписать - то есть застарелое самописное дерьмо, хреново косящее под Entity Framework. Т.е. это тоже надо переписать, а точнее безопасно удалить и заменить на EF.
2. Если Age будет нуллабле и мне нужно будет отличать варианты или объект null или возраст null (не указан), то приплыли.
Ничё не понял. Напишите пример. Если у вас есть пачка if-else или что подобное, то любая такая древовидная структура трансформируется в пачку кейсов свича (и обратно). Только не увлекайтесь этими развесистыми деревьями - когда у вас эта хрень начнёт уезжать за экран, вам предъявят, и вы сами захотите изменить со свичём.
дискард обязательно должен обрабатывать нештатные ситуации? Рассматривай его как обычный else
Любой else (т.е. дискард, дефолт и прочее "всё, что не предыдущее") может быть дальше расширен сколько угодно, если поступят такие требования. У Алекснека же требования всё возрастают - наллы во все поля повводил?
вообще пофиг. Если решение занимает вместо 15 строк всего 5, то я за
Не согласен. Не в общем случае. Есть разные строчки. Посмотри на пёрл. Вот где разгул для сокращателей. Только месяц спустя сам автор не мог объяснить что же он своим !__$@x.{__?$%x} хотел сказать. Зато одно строчка вместо 3.
5 if-else заменить на switch? Отлично. Но если мне для этого придётся писать brainfuck-подобный код, то лучше остаться с ифами.
потом мы удивляемся, почему в Германии не создаются никакие продуктов мирового масштаба.
Точно, вы открыли мне глаза, теперь я знаю отчего в Германии не очень высокая рождаемость.
Недостаток женщин с пирсингом - это же так круто и бабанькам с закостенелым мозгом это не нужно.
Рассматривай его как обычный else, не забивай себе голову.
дело то не в этом.
Во первых, switch expression лучше сравнивать с switch statement. И как часто, в части "по умолчанию", используется "это нормально".
Во вторых, условие - "всё что не проверено это хорошо" часто не очень хороший выбор. Ну вот, что будет если возраст будет отрицательным и мы это не проверили?
Любой else (т.е. дискард, дефолт и прочее "всё, что не предыдущее")
не нужно всё мешать в одну кучу.
И можно смотреть на проблему с разных сторон или с разной "высоты". Домик на земле выглядит совсем по другому, чем с высоты птичьего полета.
И если на земле может интересовать вопрос - а где входная дверь, то с высоты уже будет интересно, а не повредит ли наш домик обвал с близлежащей горы.
Или - работаю ли я один или в команде. Как мы будет решать подобные проблемы в будущем?
Не согласен. Не в общем случае. Есть разные строчки. Посмотри на пёрл. Вот где разгул для сокращателей. Только месяц спустя сам автор не мог объяснить что же он своим !__$@x.{__?$%x} хотел сказать. Зато одно строчка вместо 3.
5 if-else заменить на switch? Отлично. Но если мне для этого придётся писать brainfuck-подобный код, то лучше остаться с ифами.
Осталось только найти в моём свиче брейнфакподобный код.
потом мы удивляемся, почему в Германии не создаются никакие продуктов мирового масштаба.Точно, вы открыли мне глаза, теперь я знаю отчего в Германии не очень высокая рождаемость.
Недостаток женщин с пирсингом - это же так круто и бабанькам с закостенелым мозгом это не нужно.
Не оффтопте своими скелетами в шкафах, а то я начну про домик у моря!
Во вторых, условие - "всё что не проверено это хорошо" часто не очень хороший выбор. Ну вот, что будет если возраст будет отрицательным и мы это не проверили?
Это зависит от задачи. В математике, например, функции обычно проверяют вблизи экстремумов, а остальные значения не трогают.
Ничё не понял. Напишите пример.int? Age; - так понятней или нужно всё расписать?
Нет, вы напишите, как вы будете свои налловые сосиски (типа person?.Age?.) проверять на разные условия для Age. А я потом подумаю, как это удобно в свиче записать. А то вы просто сказали, что у вас всё налл, а как вы с этим обращаетесь - не сказали.
if(person.HasValidAge())...
А портянка внутри HasValidAge как выглядит?
а как вы с этим обращаетесь - не сказали.
говорилось...
https://foren.germany.ru/showmessage.pl?Number=40802311&Bo...
Можно еще условие на налл добавить
Т.е. проверка Age на налл делается легко и непринуждённо ещё одним кейсом.
И ещё раз - дискард с when я использую лишь в качестве костыля. Когда создатели языка дадут возможность добавлять кейсы, не привязанные к типу параметра свича, я избавлюсь от этого костыля, и станет снова всё по вашему феншую - один дискард на свич. С точки зрения компилятора, у меня и сейчас всё по феншую - один дефолтный кейс на свич. Дискард с when это не дефолтный кейс.
а вот сколько не знаем
Это всё фигня - надо кричать, что гитом в студии опасно пользоваться.
Всё время делал без студии, выбираешь любой файл и откатываешь все последние изменения. Но проблемо.
А тут работаю с компонентом у которого есть еще "подфайлы": код, разметка стилей и ява скрипт.
Ну думаю, откачу компонент (тест не сработал), так эта гадина откатила всё на исходное состояние и код и яву скрипт и стили
Т.е. вы в окошке Git Changes (справа) не можете выбрать только один файл компонента для откатывания?
В окне проектов эти части компонента могут располагаться в древовидной структуре. Но в директории они лежат все в плоской структуре, и никак не связаны. Гит отслеживает изменения не по компонентам, а по файлам. Не надо тыкать компонент в окне проектов и отменять там через контекстное меню Гита. Надо в окне изменений Гита, и отменять для каждого файла в отдельности.
Видите, те файлы, которые в окне проектов представлены типа связанными, в окне изменений - все по отдельности
Вот неправильно юзать для компонентов это контекстное меню. Надо из окошка Гита выбирать каждый файл в отдельности.
Вы ещё поди команды гитовские в консоли набираете, как упоротые линуксоиды? А надо на удобную кнопочку жмакать рядом с файликом в окошке изменений, как Виндовс-боярин.
Надо из окошка Гита выбирать каждый файл в отдельности.
А на кой мне тогда гит спаренный со студией? Так я могу и в моей любимой проге работать.
команды гитовские в консоли набираете
Как подобная глупость могла прийти в голову? Вместо контекстного меню то.
Нафига копаться в развесистом контекстном меню,
там не так уж и много. И файл вот он рядом.
А что бы добраться до кнопочки, нужно открыть/перейти в нужное окно и найти нужный файл. Вроде и фигня но лишние действия.
Тем более, что из студии делал всегда только это единственное действие - откат одного файла.
А что бы добраться до кнопочки, нужно открыть/перейти в нужное окно и найти нужный файл.
У вас коммиты всегда на десятки файлов, что вы в изменённых файлах путаетесь?
На нормальном рабочем месте все нужные окошки всегда открыты. Т.е. нужно просто передвинуть мышку и жмакнуть.
Как подобная глупость могла прийти в голову? Вместо контекстного меню то.
Гы-гы. В пятницу прибегали такие тыркатели. "Мы чо-то натыркали и там всё-всё паламаласяаааа!" Не туда ткнули когда мерж конфликты разрешали, один щелчок не на том пункте контекстного меню и мы уже выбираем "бери ours для всех". Пришлось коммиты копировать, чтобы историю не корячить. И почему мне платят в полтора раза больше чем этим тыркателям, даже не знаю :)
Про опечатки и не говорю - их не бывает в принципе.
Я тебе глаза открою - если опечатаешься, команда не выполнится. Адекватные разработчики делают параметры такими, чтобы "апичатки" не были действительными: --delete это параметр, а --dwlete - нет.
В гите я наблюдаю очень чёткую корелляцию:тупые гуисты и адекватные консольщики. У нас есть и те и те. Не значит что консольщики не делают ошибок. Но у них в 99,99% случаев хватает мозгов на запушить их на ремоут.
Это насколько надо быть причёсанным торвальдсовской сектой, чтобы адекватность оценивать по зазубриванию консольных команд...
В гите я наблюдаю очень чёткую корелляцию:тупые гуисты и адекватные консольщики. У нас есть и те и те. Не значит что консольщики не делают ошибок. Но у них в 99,99% случаев хватает мозгов на запушить их на ремоут.
А если консольщики всё же какают, то исключительно бабочками. ))
О, дополнение к кортежам. Вместо того, чтобы писать свой тип для простого объединения пачки данных, можно воспользоваться кортежем:
public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; } = new(999, "blah blah", true);
var a = Data?.TheString;
Даже record не нужен.
Единственный минус видится (ещё не пробовал) - передать такой тип данных куда-то - надо указывать всю портянку кортежа - типа
MyMethod((int, string, bool) methodParameter);
Попытайтесь ввести кортежу псевдоним... Это покажет, что даже компилятор не воспринимает данный синтаксический сахар, как нечто серьезное. Фоновое локальное решение - ок, прячем в недрах фреймворка - всем пох. Но когда такое вылазит в паблик, особенно с внешними стекхолдерами, у меня для вас плохие новости - вам останется только петь про старперов:)
Это вопрос привычки. Пока есть старпёры, которым удобнее писать развесистую лапшу с дополнительными типами, служащими лишь для хранения передаваемых данных (DTO), и длинные списки параметров методов - они будут это делать. Придут новички, которые пишут с новым синтаксисом изначально - для них код старпёров будет странным и непонятным. Как я сейчас смотрю, что человек упорно и раз за разом пишет 5-10-строчные проперти с банальными проверками на налл и присвоением параметра value, вместо использования однострочного оператора ??=. Или городит стопицот слоёв, свои прослойки, фреймворки, конвертеры и фабрики фабрик для случай "а вдруг мы заменим базу данных? а вдруг мы заменим UI-фреймворк?". Все его построения заменяются банальной трёхзвенкой, и если что будет заменено в будущем, то просто эта часть переписывается. Оттого, что он понаписал километры лапши с фабриками фабрик, он не становится умным, он становится ЗАумным. Когда он уйдёт с проекта, новый лид не будет разбираться в его лапше, а просто перепишет всё по-своему, поэтому все эти старания по размножению слоёв не стоят потраченного труда.
Что там внутри под сахаром происходит - вообще пофиг. Компилятор кучу и "старого привычного" кода превращает в свои конструкции - и что? Некоторые называют "сахаром" любые непривычные им вещи. Даже если эти новые вещи позволяют сократить запись по сравнению со старым кодом, что приводит к его большей компактности и пониманию. Т.е. используют этот термин просто как ругательство. Тогда по идее, надо бы наоборот - старую лапшу назвать "сахаром", а новые подходы - единственными и неповторимыми "тру".
эти новые вещи позволяют сократить запись по сравнению со старым кодом, что приводит к его большей компактности и пониманию
Опять подняли знамёна и идем вперед с барабанным боем?
Всегда есть различные ситуации, в одной будет лучше одно в другой другое, но главное - код не должен иметь запаха.
Все его построения заменяются банальной трёхзвенкой, и если что будет заменено в будущем, то просто эта часть переписывается.
Не следует всё радикализировать. Каждый случай имеет аргументы за и против. А смотреть на всё исключительно со своей колокольни не есть оптимальный вариант.
Можно ведь всё писать максимально просто, а если, что нужно будет изменить, просто перепишем эту часть когда надо.
Вот помню, кому-то страшно понравилось использовать синглтоны "для связи" различных частей программы - просто и не нужно ни о чём думать.
Но вот понадобилось "отвязать" одну часть...
Пример моего проекта. Изначально был написан какими-то надмозгами - полстапроектов в солюшене. Куча слёв. Всё модульное, динамичное, расширяемое шопипец. Те, кто писали проект, продали его крупной фирме и удалились. Эта крупная фирма сама поддерживала проект лишь в части написания бизнес-логики, а вся остальная кухня эксплуатировалась почти без изменений примерно 15-20 лет, пока не прекратилась поддержка платформы, на которой крутилось гуёвая часть. Никакими расширениями никто не воспользовался. Вместо этого забронзовевший код не позволял использовать современные сторонние решения, т.к. никто не знал, как заменить скажем свою самописную ORM на нормальную современную, чтобы ничего не сломалось. Надмозги несколько лет писали спагетти-архитектуру, которая во многом оказалась не нужна. И трудноподдерживаема, если ты сам не тот надмозг, который её создавал.
В результате сильно позже и другие разработчики стали в авральном темпе переписывать всё на новое, удивляясь применяемым 20 лет назад решениям. Но тоже костыльным способом - сначала самые понятные и не сильно зависимые части, чтобы чего не сломать. Т.е. пишем новый гуй на современных технологиях, но с подходами старыми, создавая кучу подгоняющей обвязки - чтобы совместимость с другими слоями осталась. И пока сохраняем самописную ORM. Когда всё будет заменено, придётся эти подгоночные костыли убирать. Т.е. переписывать проект придётся в несколько проходов по одним и тем же слоям. Гораздо проще, понятнее и быстрее было бы постепенно обновлять все части приложения, переписывая их на современный манер и выкидывая самописные костыли и оказавшиеся ненужными переусложнённые вещи. А теперь придётся делать примерно то же самое, но не постепенно, а в авральном режеме.
Так что я вашу многослойность, модули и расширяемость труба шатал. За 15-20 лет устаревает сама архитектура и её подходы - все модули и слои скопом отправляются в помойку. Не к чему подключать, нечего расширять.
Так что я вашу многослойность, модули и расширяемость...
Так о чём я и говорю, не надо всё радикализировать и обобщать. То что вам попался вариант неудачной архитектуры не означает, что везде всё так плохо с архитектурой. А вот то, что любой проект за 15-20 лет можно изменить до неузнаваемости в худшую сторону - это весьма и весьма вероятно. По крайней мере, обратного еще не попадалось.
Гораздо проще, понятнее и быстрее было бы постепенно обновлять все части приложения, переписывая их на современный манер
Опять голубые мечты... сами же написали: "сначала самые понятные и не сильно зависимые части, чтобы чего не сломать."
А что делать с непонятными и сильно зависимыми частями?
Мне непонятно, как структурированный код можно называть спагетти? Это что ошибка в терминологии? Мне непонятно стремление к переписыванию всего и вся (весь мир пытается использовать код повторно и экономить деньги). Мне не импонирует агрессивное невежество. Проекты не живут в вакууме, и тимлид, которого тут так уничижительно поминали, должен учитывать всевозможные аспекты проекта. Даже те, которые не видны с низкого горизонта джуниоров и просто не могут быть ими осознаны, в силу отсутствия опыта. Наличие множества слоев (Layered Architecture), как раз признак, того что тимлид прекрасно отдает себе отчет, что такое менеджмент изменений и как можно редуцировать риски и затраты на поддержку. Это как раз называется зрелость, один из критериев качества продукта по ISO 25010, кстати.
Тут много еще чего можно написать, но мне просто лень.:)
То что вам попался вариант неудачной архитектуры
Я думаю, что архитектура соответствовала своему времени и вполне отвечала требованиям. Потом ее бросили (ушел архитектор) и она стала дрифтовать, накапливался technische Schuld и т.д. Потом технологическая платформа устарела и всех бросили на "починку". Обычная история:)
Кстати удачность или неудачность оценивается в процессе ревью и другим архитектором. А не так как тут, поплевали на руки и оценили на раз:)
Я думаю, что архитектура соответствовала своему времени и вполне отвечала требованиям
Бессмысленно обсуждать событие основываясь на показаниях одного не очень объективного свидетеля.
Можно гадать долго и нудно.
Но, судя по тому, что есть слабо связанные и сильно связанные части я бы ставил на красное вариант неудачной архитектуры.
архитектура соответствовала своему времени
просто ради интереса и язык немного почесать
А насколько устарел труд Эрика Эванса? Или хотя бы "Алгоритмы и структуры данных" Вирта от 1984 года?
В мусор и не вспоминать?
Мне непонятно, как структурированный код можно называть спагетти? Это что ошибка в терминологии? Мне непонятно стремление к переписыванию всего и вся (весь мир пытается использовать код повторно и экономить деньги). Мне не импонирует агрессивное невежество. Проекты не живут в вакууме, и тимлид, которого тут так уничижительно поминали, должен учитывать всевозможные аспекты проекта. Даже те, которые не видны с низкого горизонта джуниоров и просто не могут быть ими осознаны, в силу отсутствия опыта. Наличие множества слоев (Layered Architecture), как раз признак, того что тимлид прекрасно отдает себе отчет, что такое менеджмент изменений и как можно редуцировать риски и затраты на поддержку. Это как раз называется зрелость, один из критериев качества продукта по ISO 25010, кстати.
Тут много еще чего можно написать, но мне просто лень.:)
Если бы вы знали юзера alex445 получше, то не задавались такими вопросами, его здесь на форуме пинают все кому не лень!
Он то университеты "Лиги плюща" - наперсточниками обзовёт, то Маска и криптомиллиардеров со своими фекалиями сравнивает.
Но достаточно посмотреть на какой стыдной машине он ездит и всё ясно и понятно, при этом очерняет Теслу и другие электрокары!
Даже на автора библии сишарпников, на Джон Скита поплеваться успел... что слишком много книжек пишет! За ответ на стековерфлоу.
Да уж, накипело у вас... Я даже не поверил сначала, что вы всерьез все это пишете.
Понапридумывают этих ваших архитектур, а людям мучаться. Действительно, проще же все переписать:)
Архитектуры работают там, где их используют правильно и со знанием дела, регулярно подновляют, заменяют в них старые технологии новыми. Т.е. когда у приложения есть хозяин, который за ним постоянно следит. Обычно это продукт, поддерживаемый одной командой без радикальной смены хозяев, на протяжении долгого времени. Т.е. это очень малое количество случаев. Во всех остальных случях сложные навороченные архитектуры, написанные по всем канонам разных "чистых кодов" и прочих "библий" программирования, в основном не работают и даже вредят, усложняют и тормозят процесс. В "библиях" об этом забывают упомянуть, рассказать неофитам правду жизни. "Ребята, вы прочитали "что такое хорошо, и что такое плохо" из мира программирования? А теперь забудьте - в большинстве случаев в вашей жизни это применяться и работать не будет." Поэтому переписать - зачастую самое правильное решение. Особенно при смене владельца, команды. Оно, вобщем-то, и используется. А все прежние старания и навороты идут прахом, какими бы гениальным и правильными они ни были.
То что вам попался вариант неудачной архитектуры не означает, что везде всё так плохо с архитектурой.
Архитектура-то как раз отличная была. Для своего времени. Я же говорю, писали надмозги. В хорошем смысле слова. Хоть и полста проектов в солюшене, но само приложение было далеко не монолит, а как сегодня модно - куча разных сервисов, работающих на разных серверах и общающихся между собой. Были сервисы, создающие динамические типы данных на лету из конфигурационных файлов, послылающие потом их на сервер приложений и создающие там эти типы активаторами. Свой сериализуемый язык запросов и самописная ORM, которые в то время (начало 2000-х) только начали пробивать себе дорогу. Свой гуёвый фреймворк, хоть и основанный на контролах ASP.NET, но сильно их расширяющий. Своё управление состоянием, когда то, что на вебсайте понавводили в формы, можно сохранить в сессию, затем в базу данных, и потом загрузить снова. И на всё это - пачка разных клиентских приложений - от веб-сайтов, до десктопа и PDA. Но времена изменились, и "гениальные" раньше подходы теперь выглядят костылями. Я поначалу тоже думал, глядя на это - кто эту хрень понаписал, зачем, люди себе работу придумывали? Потом посмотрел на технологии, почитал про них в Википедии, на года, когда они были придуманы и применялись. - Да, в своё время это выглядело революционно, на острие прогресса. А сейчас - лютая дичь, которую нужно просто выкинуть в помойку. И не поможет ей никакая архитектура, модульность, расширяемость и интерфейсы по все поля.
А насколько устарел труд Эрика Эванса? Или хотя бы "Алгоритмы и структуры данных" Вирта от 1984 года?
В мусор и не вспоминать?
Общие рекомендации вида "делай хорошо и не делай плохо" конечно не устаревают. Устаревают конкретные реализации этих рекомендаций. "Гладко было на бумаге..."
Архитектура-то как раз отличная была. Для своего времени... Потом посмотрел на технологии
Мне кажется, мы говорим о немного разных вещах.
Если приложение написано хорошо, то со временем оно не портится само по себе, его можно только испортить. Ну и используемые технологии могут устареть.
И если вначале был набор со слабо связанными модулями, то таким он и должен быть остаться. Поэтому варианта как минимум два: или вначале всё было не так хорошо, либо в процессе модификаций произошли серьезные изменения.
Мне часто встречается именно комбинация и первого и второго.
Карета отличная! Оси заменили, ободья на колёсах тоже новые, свежий лак по дереву, диваны внутри перетянули и снова набили новым пухом! Легко прошла полную реконструкцию, благодаря изначальной продуманности и модульности, заложенной в неё мастером ещё сто пятьдесят лет занад. На ней можно было бы ездить и сегодня... Только нахрен не нужно.
Задача - сделать из такой кареты современный автомобиль. Благодаря модульности, можно заменять всё по частям, и всё будет продолжать работать. Но лучше просто сделать автомобиль с нуля, а карету на помойку или в музей.
Проблема лишь в том, что в моём случае карета таки должна продолжать работать, а автомобиль из неё будут лепить, заменяя модули. При этом буквально по ходу движения кареты.
Задача - сделать из такой кареты современный автомобиль
Ну так это устаревшие технологии. Сам то принцип построения остается без изменений.
что в моём случае карета таки должна продолжать работать, а автомобиль из неё будут лепить, заменяя модули. При этом буквально по ходу движения кареты.
Какие есть более лучшие предложения с точки зрения бизнеса?
Ничего не напоминает?
Единственный минус видится (ещё не пробовал) - передать такой тип данных куда-то - надо указывать всю портянку кортежа - типа
MyMethod((int, string, bool) methodParameter);
Открой для себя интерфейсы :)
Кортежи - это хреновила исключительно для локального использования.
Пока есть старпёры, которым удобнее писать развесистую лапшу с дополнительными типами, служащими лишь для хранения передаваемых данных (DTO), и длинные списки параметров методов - они будут это делать.
Пока есть те, кто заинтересован в тестируемом коде, "старперы" будут бить "новичков" по рукм. Больно. Очень больно :)
У нас сейчас весёлая борьба нанайских мальчиков. Я предложил погромиздам голосовать за отдельные правила написания кода, они радостно имитировади бурную деятельность, предлагали правила, обсуждали и голосовали. Принятые варианты собрал им в Code Convention, а теперь... Не даю мержить изменения, нарушающие договорённости.
Полярная лиса подкралась к коболистам незаметно. Они думали что будет как обычно. Что написано в проектной документации никого не интересует :)
И теперь два 50+ мальчика обиделись. Страдают над тикетами, к которым я уже две недели как написал всё, что они должны поправить. Но править их код у них... Нет времени. Они уже всё написали, а гадкий я не пускаю в релиз. Это провокация! Из-за меня в релиз не уйдёт супер важная фича!
Ходим по кругу. Сегодня 3й раз "побеседовали":
- когда аппрувишь мой код?
- когда приведёшь в соответствии с требованиями.
- а кто тебе дал право требовать!!!???
- команда. Мы сами установили наши требования и свели их в code conventions
- а у меня нет время на эти глупости!
- ну, найди время
- а я не должен!
- Должен. Код не пройдёт в релиз, пока не будет соответствовать правилам. Если хочешь поменять правила, на следующем ретро можешь обсудить.
- я буду жаловаться! (так и хочется добавить "прокурору!" :))
Две недели назад первый раз так побеседовали. Потом тишина на неделю, и новая итерация. Романтика.
Она не то что не выглядит... Она у нас как в привокзальном туалете. Руками пощупать можно. У нас просто 4 Олёша-подобных разработчиков. Самые умные. "Чо ты мне своей арзитектурой тычешь". Которые 10-20 лет писали на коболе, потом за 3 дня "научились" писать на яве и теперь уже 5 лет пишут так, как научились за эти три дня.
Но так как у них лужёные глотки и "авторитет" они задавили всех остальных, что те не крякают. Сидят как мышь под веником, не отсвечивают. Но никто не понимает что же эти 4 гения написали. В результате остальные "разрабатывают" с помощью копипасты.
А я пытаюсь это сломать. Заставляю гениев писать документацию, чтобы другие понимали что же делает этот метод с 7 параметрами. В процессе написания
гении даже приходили к мнению что оказывается все 7 и не нужны... И (о боже!) заставляю их переименовывать переменные, методы и классы, чтобы имя хоть немного соответствовало тому, что они делают. В общем отношусь без должного пиитета. У олёшенек подгорает и они устравивают подковёрную борьбу :)
Это может быть совершенно обычный код без криминала.
У нас например в кодинг стандартах написано, что сначала должны быть перечислены все using System.*, потом все остальные. Разумное это требование или нет - вообще не важно.
Есть стандарт кода и ему надо следовать. Если не нравится - нет проблем, стандарты кода можно поменять, но им все равно надо следовать.
В данном случае скоманда сама сформулировала для себя требования к коду, но некоторые члены комманды считают себя ровнее :)
то таким он и должен быть остаться.
---------------
почему?
мой заводик помнишь? переход с оракла на постгрее... и коннективити под постгрее обрабатывающая ошибки... оракла.
Все всегда делается в меру понимания исполнителем и чаще всего исполнитель не интересуется архитектурой
У нас сейчас весёлая борьба нанайских мальчиков. Я предложил погромиздам голосовать за отдельные правила написания кода, они радостно имитировади бурную деятельность, предлагали правила, обсуждали и голосовали. Принятые варианты собрал им в Code Convention, а теперь... Не даю мержить изменения, нарушающие договорённости.
Полярная лиса подкралась к коболистам незаметно. Они думали что будет как обычно. Что написано в проектной документации никого не интересует :)
И теперь два 50+ мальчика обиделись. Страдают над тикетами, к которым я уже две недели как написал всё, что они должны поправить. Но править их код у них... Нет времени. Они уже всё написали, а гадкий я не пускаю в релиз. Это провокация! Из-за меня в релиз не уйдёт супер важная фича!
Ходим по кругу. Сегодня 3й раз "побеседовали":
- когда аппрувишь мой код?- когда приведёшь в соответствии с требованиями.
- а кто тебе дал право требовать!!!???
- команда. Мы сами установили наши требования и свели их в code conventions
- а у меня нет время на эти глупости!
- ну, найди время
- а я не должен!
- Должен. Код не пройдёт в релиз, пока не будет соответствовать правилам. Если хочешь поменять правила, на следующем ретро можешь обсудить.
- я буду жаловаться! (так и хочется добавить "прокурору!" :))
Две недели назад первый раз так побеседовали. Потом тишина на неделю, и новая итерация. Романтика.
Прямо "Санта-Барбара".
В процессе написания гении даже приходили к мнению что оказывается все 7 и не нужны... И (о боже!) заставляю их переименовывать переменные, методы и классы, чтобы имя хоть немного соответствовало тому, что они делают.
А время на конструирование абстрактных фабрик для абстрактных фабрик остаётся? Если ещё скажете, сколько примерно зарабатывают ваши "ветераны", будет совсем хорошо.
Чёта мне кажется, что даже у меня ситуация получше. ))
Это может быть совершенно обычный код без криминала.
У нас например в кодинг стандартах написано, что сначала должны быть перечислены все using System.*, потом все остальные. Разумное это требование или нет - вообще не важно.
Есть стандарт кода и ему надо следовать. Если не нравится - нет проблем, стандарты кода можно поменять, но им все равно надо следовать.
Разве нет штуки, которая сама сортирует юзигни по вашему шаблону после любой команды автоформата (ctrl + K, D, например)?
У меня обычно этими юзингами почти полный экран засориться может. Ещё после рефакторинга могут быть дырки между ними (после удаления строк). Я всю портянку с юзингами просто сворачиваю. После появления в Студии фичи автодобаления юзингов, я туда даже смотреть перестал. Максимум, если какой конфликт имён классов. Но это тоже не требует уделять внимание юзингам - просто соглашаешься на какой-нибудь предложенный Студией рефакторинг, типа добавить полное имя класса.
Вот бы кто подсказал, как в Студии удалить строку без замены её на пустую строку. Я обычно использую окошко "найти-заменить", где в "заменить" оставляю пустое место. Но это оставляет пустые строки в коде.
Наф оно нужно вообще?
От куда ж мне знать? :) Но требование такое есть. Будь любезен исполнять.
Это ещё тупее, чем "пробелы против табов".
Пробелы против табов - это как раз не тупо. Тут важно, чтобы у всех были одинаковые настройки. Если у кого-то настройки отличаются, то трындец.
можно пример кода, который ты не пускаешь в прод из-за нарушений конвенции?
Как уже отметили, совершенно обычный код, без особого криминала. Просто нарушающий принятые соглашения. Если я с криминалом нахожу, мне никакие конвеншены не нужны :)
Например, вот такая фигня (кто на яве пишет, поймёт, остальным поясню, имя класса поменял, мало ли, Datenschutz и всё такое):
/** * identisch zu * @param adresse AdresseMitLand */ public Boolean identischZu(AdresseMitLand adresse) { return true; }
Начинаем с вопроса - а нафига мне метод сравнения, которые ничего не сравнивает? Нет ответа. Почему в документации не написано, мол, временная реализация, в настоящий момент, говорит что все всем равны, но надо использовать там-то и там-то потому что в будущем будет заменено.
Где описание параметра, где описание результата? Метод-то публичный.
Почему Boolean? (объект - оболочка вокруг примитивного типа boolean). Он может быть null. Зачем нам такое счастье? Мы (даже в конвенции написали) "используем примитивные типы если нет причин использовать врэпперы, причина описывается в документации".
До сих пор всё такое счастье тупо коммитилось, потом проходило 3 года и все сидели чесали репу а нафига ж такое сотворили, и чего хотели этим сказать.
нафига мне метод
------
Как зачем?
Дырку в интерфейсе затыкает...
даже в конвенции написали
------
Ну это только из-за объема писанины/поддержки.
Есть охрененные преимущества когда все элементы строго типизированы - просто дооределяешь что можно делать и не беспокоишься, скажем, об сложение количества чего-нибудь с телефонным номером... причем - на этапе трансляции.
Наф оно нужно вообще?От куда ж мне знать? :) Но требование такое есть. Будь любезен исполнять.
Проверка на лояльность? Типа, скажи ему регулярно повторять какую-нибудь ненужную фигню, чтобы отнимала время и действовала на нервы. Если согласится, значит покладистый - берём
Где описание параметра, где описание результата? Метод-то публичный.
Зачем разливать воду там, где и по названию метода всё понятно?
Понятно, почему это делают всякие Микрософты и им подобные - у них платят за жопочасы и строчки быдлокода. Они могут потратить недели на обсуждение этих ваших пробелов или табов, проводить многоуровневые исследования фокус-групп, и не написать за месяц ни строчки кода. При этом все - солидные такие шестизнаки. А ваши-то шараги куда со свиным рылом в калашный ряд пруться?
Все всегда делается в меру понимания исполнителем и чаще всего исполнитель не интересуется архитектурой
Угу,.. исправить, исправили, сейчас работает, а что будет потом уже не интересует.
Обращаешь внимание, - а какого переписывать и так всё работает.
До сих пор всё такое счастье тупо коммитилось, потом проходило 3 года и все сидели чесали репу а нафига ж такое сотворили, и чего хотели этим сказать.
Спасибо
Только это скорей правила оформления кода, чем coding standards. Тут старперы наверняка вперед всех.
Проверка на лояльность? Типа, скажи ему регулярно повторять какую-нибудь ненужную фигню, чтобы отнимала время и действовала на нервы. Если согласится, значит покладистый - берём
А кто оценивает нужность / ненужность фигни? :) Безотносительно этого примера.
С нужностью-ненужностью фигни как с кодом - если через какое-то время никто не может объяснить, зачем эта фигня нужна, значит что-то не так со стандартами этих ваших фигней. Если при этом все продолжают делать эту фигню (потому что "так деды завещали"), то не так уже и с вами. При этом мантра "работает? - не трогай!" не работает.
Только это скорей правила оформления кода, чем coding standards. Тут старперы наверняка вперед всех.
Я под "правилами оформления кода" понимаю правила вроде "строчка не длиннее 140 символов", или "сначала в классе идут публичные, потом приватные" или "после } перенос строки". Но всё равно всё это тоже Coding Convention.
Тут старперы наверняка вперед всех.
Если б. У них у каждого своё мнение. Каждый пишет как ему нравится. Но именно в оформлении без больших расхождений. Потому что разобраться не смогли как настройки форматтера в эклипсе поменять :)
Проверка на лояльность? Типа, скажи ему регулярно повторять какую-нибудь ненужную фигню, чтобы отнимала время и действовала на нервы. Если согласится, значит покладистый - берём
Все эти детали полезны для того, чтобы избежать вкусовщины.
Один вставит юзинг и забудет. Другой будет сортировать изинги по длине. Третий по алфавиту. Четвертый по каким-нибудь другим признакам. И жопа начнется, когда все эти люди начнут (а рано или поздно они начнут) форматировать уже написанное под себя.
разобраться не смогли как настройки форматтера в эклипсе поменять
А тут меньше чем надо? Один раз настроил и пользуй везде. Для шарпа сделано довольно хорошо, предполагаю, что для явы не хуже.
https://www.jetbrains.com/help/idea/configuring-code-style...
Я под "правилами оформления кода" понимаю правила вроде "строчка не длиннее 140 символов", или "сначала в классе идут публичные, потом приватные" или "после } перенос строки". Но всё равно всё это тоже Coding Convention.
Тогда это хрень полная. Вы бетонируете какие-то фарисейские принципы, зачастую мешающие нормальной работе. В некоторых случаях удобно писать, группируя по смыслу - поля и свойства, например. Т.е. приватную и публичную часть рядом друг с другом. А иногда и методы туда же - в инициализацию объекта пихаю реализацию делегата, созданную тут же через лямбду. Типа такого (отвлечённый пример на Сишарпе)
Person somePerson; public Person SomePerson => somePerson ??= new() { Age = 20, Name = _ => Age > 5 ? Person.DefaultName : "Baby", Condition = (Guid id, string defaultCondition) => { var realAge = GetRealAge(id); return realAge > 100 ? "died" : defaultCondition; }, };
По вашим правилам я должен эти несколько коротких строчек разнести в три разных места класса - приватное поле somePerson в определение полей, свойство для него - в публичные свойства, и ещё в месте для методов написать пару методов для получения имени и состояния. А потом бегать-мотаться по всему классу, выясняя, как же инициализируется свойство. А у меня - всё в одном месте.
А не так давно мы ещё выяснили, что такая запись многим неприемлема - нужно расписать всё с явными геттерами, явной проверкой на налл (без оператора ??=) и без лямбд. Т.е. накатать кода где-то на полэкрана, разнесённого в три разных места класса.
Мне это ещё в плюсах не нравилось - чтобы понять, как работает класс, где у него что находится, нужно открыть минимум ДВА файла. Может, в 80-90-е это и было круто, но сейчас и уже давно это смотрится как костыльный анахронизм, мешающий работать.
Тогда это хрень полная. В некоторых случаях удобно писать...
А в некоторых случаях так, а может и так... в итоге каждый пишет как ему удобно, под настроение на сегодня.
А теперь возьмем команду, в которой каждый пишет как хочет, насколько быстро можно будет читать код другого человека?
Ну а про приведенный код я лучше промолчу
Код отвлечённый, как я сказал. Просто нужен был любой пример с методом без параметров и с парой параметров, однострочный и в несколько строчек. Главное, что методы не определяются где-то в другом месте класса, а пишутся тут же лямбдами. А ленивая инициализация - это вообще уже давно привычная тема. Чем код не нравится?
насколько быстро можно будет читать код другого человека?
Мой код можно понять очень быстро, т.к. всё компактно и в одном месте. А вот если распихать его кусками по всему классу, то придётся прыгать по нему, теряя контекст.
Если метод большой - 5+ строчек, то я выношу его отдельно. А так у меня в проекте часто встречается, что нужно инициализировать объект в том числе кучкой коротких методов (делегаты). Выписывать их где-то вдалеке, а не по месту - просто плодить лапшу в коде.
Если не нравится конкретный код, вот можно более абстрактный
Person somePerson; public Person SomePerson => somePerson ??= new() { Property1 = 20, Property2 = _ => ..., Property3 = (param1, param2) => { ... ... ... }, };
Обычно код читается за один проход без задержек.
Что-то тривиальное.
Фабрика фабрик у вас тоже за один проход, без задержек?
Здесь же нужно задумываться на любой строке.
У вас вызывают затруднения одна однострочная функция и одна двухстрочная? Или в присвоении константы вы видите скрытые смыслы? Может, оператор ??= слишком нов и загадочен для вас? Ленивая инициализация - откровение? ))
Общую концепцию я бы не стал трогать, как и правильную последовательность вызовов.
Но подобную конструкцию вижу в первый раз "Property2 = _ =>"
И каким образом
public Func<object, string> Property2 { get; set; }
превращается в
public string Property2 { get; set; }
пока не додумался Как и откуда берутся параметры для Property3?
Общую концепцию я бы не стал трогать, как и правильную последовательность вызовов.
Но подобную конструкцию вижу в первый раз "Property2 = _ =>"
И каким образом
public Func Property2 { get; set; }
превращается в
public string Property2 { get; set; }
пока не додумался Как и откуда берутся параметры для Property3?
Всё там нормально - никаких
public string Property2 { get; set; }
там нет. Name и Condition это делегаты, возвращающие строки. Просто название неудачное, что непонятно, что это не просто свойства.
Параметры берутся при вызове этих делегатов:
string name = SomePerson.Name(anyAge); string condition = SomePerson.Condition(id, "alive");
Я вам ещё раз говорю - не привязывайтесь сильно к коду. Я лишь хотел показать, как будет выглядеть то или иное использование. Первый случай - нужен делегат с параметров, а у меня есть вариант метода или лямбды без параметра. Ну я и использую дискард. Второй случай - не совсем верно я по памяти написал. Но тут просто хотел показать вариант, когда метод не однострочный и с более, чем одним параметром - т.е. вроде бы громоздко должно выглядеть, но на самом деле не очень.
По идее, если всё свойство или метод укладываются в один экран, то вы не теряете контекст работы этого свойства - вы видите всё от и до. А вот когда у вас ссылки на методы, разбросанные по классу, то вам надо прыгать на эти ссылки, чтобы глянуть, что там происходит - вы теряете контекст.
Фабрика фабрик у вас тоже за один проходПодобные конструкции создают извращенцы, которые пока по счастью не попадались.
Да ладно? А по мне, так подавляющая часть всяких инверсий зависимостей - это как раз извращения. Чтобы понять, как работает та или иная хрень, написанная с помощью инверсий, нужно либо попрыгать по классам, либо иметь возможность открыть штук 5-10 окон с кодом в параллельном режиме (не знаю ни одной IDE с такой возможностью), чтобы видеть весь код сразу. Особенно этим страдают всякие инжекции и шаблонные методы. Оно может хорошо работает, но понять эту хрень зачастую очень сложно, особенно когда создатель почти не оставил комментариев. И особенно если эти инженкции не в чистом виде, как в рафинированных примерах, а разбавлены прочим кодом и паттернами.
В примере моего реального приложения там были объекты-модели для гуёвых контролов, и у каждой такой модели была пачка делегатов для установки свойств гуёвого контрола в зависимости от условий. И вот методы для этих делегатов были в основном 1-4 строчными. И мне было проще и понятнее писать эти методы прямо в создании этих моделей для контролов, чем раскидывать их по модели всей гуёвой формы. Т.е. не так
FormModel { Control1 Control2 ... Methods for Control1 Methods for Control2 ... }
а вот так
FormModel { Control1 { Methods for Control1 } Control2 { Methods for Control2 } ... }
В реальности в модели формы ещё полно другого кода, так что делегаты там просто теряются, и получается, что инициализация каждого контрола раскидана по всей модели формы.
Свой пример чего? :)
Твой пример - неместируемое говно.
А если учесть, что
Name и Condition это делегаты
так это еще и хрен поймешь в каком месте программы и за что отвечает сей объект.
Person somePerson; public Person SomePerson => somePerson ??= new() { Age = 4, Name = _ => Age == 4 ? "car" : "some other vehicle", Condition = (Guid id, string defaultCondition) => { return id.GetHashcode() % 2 == 0 ? "Tank Full" : "Damaged engine"; }, }
а потом так:
Person somePerson; public Person SomePerson => somePerson ??= new() { Age = 2, Name = _ => Age > 0 ? "Lion" : "Bird", Condition = (Guid id, string defaultCondition) => { var realAge = GetWhatEverById(id); return realAge > 100 ? "Healthy" : "Pink"; }, };
Флаг в руги к крест на могилу при отладке этого говна.
Я спросил ваш вариант, если у объекта есть делегаты, которые нужно инициализировать. Вы же не против делегатов в принципе? У меня делегаты инициализируются лямбдами прямо в инициализаторе объекта, при этом инициализация ленивая. Ещё можно написать отдельные методы и назначить их делегатам. Можно в инициализаторе объекта, а можно после вызова конструктора. Тут не вопрос, будут ли делегаты в принципе - они есть, и вы с этим поделать ничего не можете.
В чём проблема отладки? У вас отладчик в этих строчках кода не остановится?
Чтобы вы не придирались к возможному наобум придуманному конкретному коду, я написал более абстрактно, где обозначил, что важно лишь то, где определены функции, которыми инициализируются объекты. Но вы все проигнорировали это, а стали прицепляться к невылизанности кода. Вместо этого конкретного кода может быть любой другой. Поэтому я и сказал - вставьте свой по вкусу, ваш вариант. Главное, что тут у объекта свойство-делегат, и нужно ему назначить какой-то метод.
Вы же не против делегатов в принципе?
Я против делегатов. Делегаты дают настолько большую свободу использования и интерпритации, что ну его нахрен. Вообще, я не припомню ни одного случая, когда было бы разумно использовать делегаты... ну кроме пожалуй call back функций, которые не используются уже лет 500.
и вы с этим поделать ничего не можете.
Убить того, кто везде с поводом и без ляпая делегаты :)
В чём проблема отладки? У вас отладчик в этих строчках кода не остановится?
Отладчик в этих строчках остановится. А вот в каких местах эти делегаты будут вызваны? Какие там зависимости? Как и самое главное что при таком подходе отлаживать?
Собственно говоря, с таким подходом вообще не нужены ни классы, ни структура, ни архитектура. Просто желаешь
God-объект и добавляешь в него делегаты с разными параметрами. Дальше твоя задача просто вызывать эти делегаты в нужной последовательности. Ну и проинициализировать твой God-объект :)
Я против делегатов. Делегаты дают настолько большую свободу использования и интерпритации, что ну его нахрен. Вообще, я не припомню ни одного случая, когда было бы разумно использовать делегаты... ну кроме пожалуй call back функций, которые не используются уже лет 500.
Гуй. В том числе гуёвые модели в паттернах типа MVVM, MVP, MVC и т.п.
И в принципе все случаи, когда надо реагировать на какое-то событие - пришли данные в канал, добавились данные в БД, какой-то чувак нажал на кнопку. Альтернатива какая событиям? В бесконечном цикле отслеживать флаги наступления этих событий?
и вы с этим поделать ничего не можете.Убить того, кто везде с поводом и без ляпая делегаты :)
А я люблю делегаты! Я их на хлеб каждое утро мажу, и даже засыпаю с парой больших плюшевых делегатов в обнимку.
Вообще, вы казались раньше, со стороны, крутым дядей-программистом. Сеньёр-помидор, гроза джунов, отец миддлам. А в шкафу банальные скелеты - зачморён делегатами. Это, кстати, и остальных тут типа-крутых типа-сеньёров касается. ))
Гуй. В том числе гуёвые модели в паттернах типа MVVM, MVP, MVC и т.п.
Там используются event'ы. Эвенты используют делегаты, но разница между ними огромна.
Альтернатива какая событиям?
Эвенты используют делегаты, но разница между ними огромна.
Если в 2-х словах:
An Event declaration adds a layer of abstraction and protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list.
Тут не вопрос, будут ли делегаты в принципе - они есть, и вы с этим поделать ничего не можете.
Вот в этом и есть главная проблема.
Когда в Си пользовали косвенные вызовы процедур/функций, то это как то еще можно было понять (и простить )
Но в шарпе? и повсеместно...
Уверен, что если Вы чуть больше подумаете в этом направлении (убрать нахрен эти делегаты), то наверняка найдете более разумное решение.
А по мне, так подавляющая часть всяких инверсий зависимостей - это как раз извращения.
Когда и я так думал, когда привык ставить точку останова в конструкторе и смотреть откуда приходят все параметры.
Но времена меняются и слабое связывание оказывается гораздо полезнее.
Наверняка и MediatR и FluentValidation и пр. считаете извращениями вместе с чистым кодом и чистой архитектурой. Народ просто хочет подзаработать и махает этим перед носом тупых осликов.
А мы умные, будем делать правильно без всей этой надуманной научной чуши.
Параметры берутся при вызове этих делегатов:
Да, потом уже дошло это извращение. Обычно ожидается увидеть инициализированный объект в подобном случае и инициализированный данными, а не какой то фигнёй.
там были объекты-модели для гуёвых контролов, и у каждой такой модели была пачка делегатов для установки свойств гуёвого контрола в зависимости от условий.
Ладно, не будем придираться что МОДЕЛЬ имеет КОНТРОЛЫ. Но получается, что каждый контрол работает по разному в зависимости от того где он используется. Что по идее приводит к тому, что и контролы и модели становятся сильно связанными.
Эвенты используют делегаты, но разница между ними огромна.
Если в 2-х словах:
An Event declaration adds a layer of abstraction and protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list.
Надо такой вопрос на собесах задавать, когда хочешь кого-то завалить. Особенно пояснить за "огромна", хотя всё объясняется в "двух словах".
Просто для сеньоров-помидоров SOLID не пустой звук.
Там больше половины - маркетинг для сектантов, чтобы по сцене ходить и втирать, и лишь небольшая оставшаяся часть катит. ))
Проблема этого солида в том, что его можно слишком широко интерпретировать. Это просто мантры с возможностью широкого толкования. Ляпнуть со сцены с примерами из разряда песочниц - это одно. А сделать и применить это всё правильно в реальном коде в конкретных ситуациях - другое. И у каждого перезрелого помидора своё видение этого солида. Посади пачку помидоров в одну теплицу - они же передеруться, и каждый другого выгонит из профессии. ))
Уверен, что если Вы чуть больше подумаете в этом направлении (убрать нахрен эти делегаты), то наверняка найдете более разумное решение.
Делегаты лучше ваших сраных инжекций, т.к. не требуют создания дополнительного объекта для вызова функций. Можно цеплять функции напрямую. Вообще, есть поверье, что инжекции изобрели (или развили до маразма) всякие джависты, у которых на заре Джавы не было нормальных инструментов в языке, типа делегатов. А может и сейчас нет - кто этих отщепенцев знает. ))
В некоторых случаях удобно писать, группируя по смыслу - поля и свойства, например. Т.е. приватную и публичную часть рядом друг с другом.
Думаю , когда вы поймете, для чего именно разделяли и разделяют публичную и приватную части в имплементации и расставите верно приоритеты в своем подходе к разработке кода, вы сможете претендовать на существенную прибавку к своей зарплате (но это не точно, но я так думаю) :)
И для чего же? Для внешнего потребителя класса пофиг, как там внутри всё расставлено - он видит лишь публичную часть. А для разработчика этого класса всё должно быть расставлено так, как ему удобно, а не как кто-то со сцены наплёл.
Если вопрос о повышении моей зарплаты будет решаться по тому, как я расставляю всякую фигню в своих классах, мне лучше уйти из этого места... Хотя, если за простую расстановку всякой фигни можно получить сверху неплохо так денег - почему бы, чёрт возьми, и нет? Ну хочет кто-то платить за фарисейство - пожалуйста. Пока не найду вариант получше.
12 год - да наф нам не нужон этот ваш делегат.
14 год - Джава 8 представляет лямбды и ссылки на методы.
Можно ещё тут почитать срачи.
Короче, городили паттерны богу паттерны из-за отсутствия нормальных инструментов. Инструменты появились, а говнопаттерны остались. Вышедшие в тираж старички попёрлись на сцены вещать о своих старых паттернах, хотя новые инструменты позволяют зачастую выбросить это старое дерьмо на помойку. Не всё, конечно, но некоторое.
Делегаты лучше ваших сраных инжекций, ...
откуда такая агрессия?
Если считаете, что ваше решение самое лучшее, ну так пожалуйста, нам не жалко.
Жалко будет тех кто придёт потом, но это также не наша проблема.
Я думал, что всегда хорошо глянуть на проблему с разных сторон.
для разработчика этого класса всё должно быть расставлено так, как ЕМУ удобно,
Вот пожалуй в этом и есть вся суть данной дискуссии.
А удобно то должно быть команде, как текущей так и следующей. И это самый минимум, что хочется иметь от хорошего кода.
откуда такая агрессия?
Это не агрессия, это "добавить перчику в бульон - для вкуса". Это я только в интернете такой, а в жизни ваще нифига не агрессивный. ))
Если считаете, что ваше решение самое лучшее, ну так пожалуйста, нам не жалко.
Мне этого мало. Я хочу влезть в чужой монастырь, разнести там всё, и заставить всех плясать под свою дудку. Шутка.
Короче, городили паттерны богу паттерны из-за отсутствия нормальных инструментовПонятно. Банда четырёх с автоматами еще не попадалась на пути
Почему не попадалась? Где-то в таком месте встречал.
Это я только в интернете такойРеального персонажа дано знать не всем, поэтому впечатления остаются интернетные.
Ну типа: Ложки-то нашлись, а осадок остался
Так вы не узнаете, что это я к вам пришёл. Мало ли всяких Алексов вокруг шляется. Ну или можете сделать вид, что не узнали.
Где-то в таком месте встречал.
ну так поэтому и высказывается данное мнение, потому как если бы остался автомат перед глазами, подобных высказываний бы не было.
Так вы не узнаете, что это я к вам пришёл.
Узнаем, узнаем. Тут один приходил на интервью, говорил, что лучший разработчик в мире, так как его на гитхабе котируют дюже. Токсичный, наглый, короче всех старперами обзывал и революцию в матрице обещал. Не взяли, увы. Не вы были?:)
Надо такой вопрос на собесах задавать, когда хочешь кого-то завалить.
Если кандидат не знает почему для нотификации следует использовать эвенты, а не делегаты, то гнать в шею надо такого кандидата :)
А если программист повсеместно использует делегаты, то надо гнать в шею такого программиста. Все просто.
Делегаты лучше ваших сраных инжекций, т.к. не требуют создания дополнительного объекта для вызова функций. Можно цеплять функции напрямую.
Еще раз. Зачем у тебя вообще есть разные классы?
Сделай себе контейнер с делегатами и замени 99% кода на этот контейнер.
Вообще, есть поверье, что инжекции изобрели (или развили до маразма) всякие джависты, у которых на заре Джавы не было нормальных инструментов в языке, типа делегатов.
Инжекты нужны для того, чтобы была возможность подменять объекты. Это активно используется как продуктивном коде, так и в тестировании.
Я на русском программирование не учил, делегаты это все что Func<…> и Action<…>?
Оно и на английском делегаты - delegates. ))
Делегаты это делегаты. Func и Action это готовые определённые типы делегатов, которые широко используются внутри Дотнет фреймворка. Ну и их можно использовать, чтобы не писать велосипеды - в конце-концов, для всех методов с одним входных параметром и без возврата достаточно типа Action<T>. Но судя по коду, что я встречаю, почти все пишут свои определения для банальных делегатов. Вобщем, народ букварей не читает, чего во фреймворке есть не отдупляет, но на собесах по бумажкам какую-то заумь спрашивает. ))
Надо такой вопрос на собесах задавать, когда хочешь кого-то завалить.Если кандидат не знает почему для нотификации следует использовать эвенты, а не делегаты, то гнать в шею надо такого кандидата :)
А если программист повсеместно использует делегаты, то надо гнать в шею такого программиста. Все просто.
Я же говорю - передерутся и выгонят друг друга из профессии. И останутся одни со своим говнокодом на проекте, и лишь покладистыми инфантильными подопечными. Не забывая при этом их метелить, какие они говнокодеры и ничего не понимают. А начальству будут втирать, что нет на рынке нормальных, умных, достойных. ))
12 год - да наф нам не нужон этот ваш делегат.
На всякий случай, Ололёшеньке всё равно, он у нас дурачок, по-англицки читать это не его, но вдруг кого удивило.
Во-первых, статья 1997-8 года. Не позднее. Java 1.2 не упоминается. Ну, ашипся ололёшенька. Бывает. (Статья про J++. Кто такое мелкомягкое уродство помнит?)
Во-вторых, суть статьи "нафиг усложнять VM ссылками на методы, если есть внутренние классы".
Ну и, в-третьих, ...
14 год - Джава 8 представляет лямбды и ссылки на методы.
"Ссылка на метод" в 8-й Яве это не "delegate". Это синтаксический сахар. Который компилятором преобразуется... во внутренний класс. Как и лямбда.
Во-первых, статья 1997-8 года. Не позднее. Java 1.2 не упоминается
Согласен, спутал - в 2012 году это было заархивировано, а не выпущено. Но сути это не меняет - до последнего "нам не нужны делегаты", а потом резко "но если очень надо, то вот вам имитирующие костыли".
Так никто и не говорит, что в Джаве есть нормальные делегаты и лямбды. Так, лишь жалкая пародия. Непонятно, зачем их ввели в такую лучшую и совершенную Джаву - наверное, зумеры заколебали - "а вот в Сишарпе и других современных языках...", вот им и бросили кость. А так бы старпёры до сих пор сидели на старых версиях и довольно рыгали бы на форумах - "а нам даже за поддержку старого говна платят больше, чем вам, гы-гы!". Просто Оракл понял, что если сейчас не оторвать свою жопу от насиженного дивана, то Джава окончательно сдохнет вместе со своими старпёрами. Старпёрам может до пенсии бы их зарплат хватило, а вот Ораклу - нет, если он намерен этих старпёров пережить без сокращения бизнеса. По сути, единственная существенная тростинка, на которой она до сих пор держится - Гугл со своим Андроидом. Без него и новых версий Джавы со всем этим сахаром вакухи по Джаве усохли бы в разы.
Кстати, у Джавы и проблемы есть с несовместимыми версиями - тут можно так писать, а тут нельзя. Раньше множество имплементаций виртуальных машин считалось благом, а теперь понятно, что это дурь, и всё равно будет один фаворит и куча догоняющих, которые никому не нужны. Пока в Джаве всё ещё сидит куча народу, это как-то незаметно. По мере её усыхания эта раздробленность будет сказываться всё больше.
Но сути это не меняет - до последнего "нам не нужны делегаты", а потом резко "но если очень надо, то вот вам имитирующие костыли".
Утомил тупостью, чесслово. Ещё раз: в статье было про то, что расширять/усложнять VM поддержкой ссылок на методы НЕ НАДО, потому что то же самое можно делать внутренними классами.
"потом резко, очень надо" - это твоя дурь. Синтаксический сахар добавляется постоянно. То ссылки на методы, то записи.
Всё остальное комментировать не имеет смысла. Ололёшенька в своём репертуаре, брехня.
Делегаты это делегаты. Func и Action это готовые определённые типы делегатов, которые широко используются внутри Дотнет фреймворк
ну как я и говорю
delegate void MyMethod(string message) это эквивалент Action<string> MyMethod
или
delegate int MyFunc(string message) это Func<string,int> MyFunc
я бы хотел узнать у староверов, как бы они закодили вот такую хотелку
есть энтити класс Person, хочу функцию, которой я мог бы апдейтить любое свойство объекта Person в базе данных, доступ к объектам по айди
в статье было про то, что расширять/усложнять VM поддержкой ссылок на методы НЕ НАДО, потому что то же самое можно делать внутренними классами.
"потом резко, очень надо" - это твоя дурь. Синтаксический сахар добавляется постоянно. То ссылки на методы, то записи.
Так не надо, что они эти ссылки на методы и лямбды добавляли аж с версии 1.х - сколько там, больше 15 лет прошло? А чего раньше не добавили, раз это всё уже считай было и можно было легко сделать "внутренними классами"? Уверен, не дай им Сишарп и другие современные языки пинка под зад, они бы до сих пор шамкали "не надо, нам и так хорошо!".
Гуй. В том числе гуёвые модели в паттернах типа MVVM, MVP, MVC и т.п.Там используются event'ы. Эвенты используют делегаты, но разница между ними огромна.
Альтернатива какая событиям?Эвенты используют делегаты, но разница между ними огромна.
Если в 2-х словах:
An Event declaration adds a layer of abstraction and protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list.
Т.е. события основаны на делегатах. Т.е. без делегатов никуда. Ну и чего бухтеть "убил бы, убил бы"?
Что есть в той же Джаве по событиям, на чём они там основаны?
Обычные методы с параметрами на каждый подобный чих. Ну и возможность самому ещё расширить это дело. До этих делегатов и лямбд такие методы вроде даже автоматически по шаблонам генерились - к каждому дата сету генерилась пачка методов на несколько тысяч строк в среднем.
Альтернатива какая событиям?
-----
Альтернатива называется WinProc.
У меня сейчас сильно перегружен лапоть.
А при написании экранной клавы как раз пользовались делегатами.
Результат - нажимаю Шифт, нажимаю букву...буква выводится не в том регистре.
а чтобы было совсем смешно - лечить надо заменой... БП и акку...
Но я против того, чтобы делегатам назначались методы самого класса - это способ подключения внешнего решения и пусть таким и остается.
А где вы видели, чтобы делегатам-членам класса назначались методы-члены этого же класса? Какой в этом смысл? Почему бы сами методы не использовать?
Когда я в своём примере использую лямбды в инициализаторе объекта, то это извне класса, объект которого создаю.
есть энтити класс Person, хочу функцию, которой я мог бы апдейтить любое свойство объекта Person в базе данныхпофигу в какую группу попадаю, но такую хотелку просто-бы отмели в зародыше.
Он намекает на EF с его возможностью повставлять делегаты в функции запросов. Вы сейчас будете отрицать, что используете это? ))
использую лямбды в инициализаторе объекта
А давайте глянем на это немного "сверху".
У нас есть объект который нифига не умеет, а всё поведение мы задаем ему сами.
Обычно делают так:
https://medium.com/@kevinkuan_26362/back-to-basic-designin...
Но нам это нафиг не нужно, сделаем все сами, чтобы можно было закинуть всё что угодно, в любой комбинации и без тестов
Делегаты там в принципе используются везде
Не имею понятия, для себя не пользую, вот нашел какой то примерчик. Покажите плиз...
https://github.com/SeanLeitzinger/Entity-Framework-Core-Ex...
в одном месте тебе нужно изменить дату рождения человеку, в другом имя, в третьем адрес.
Так реализовывать в принципе не буду, всё должно быть в одном месте, а объект всегда иметь определенное состояние.
где то так - "Aggregates are the basic element of transfer of data storage — you request to load or save whole aggregates." MF
Хотя в зависимости от конкретики возможны варианты.
Вот рекомендации например:
https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/...
Никаких извращений
А визуально может быть так как и описано.
Но если сильно хочется атомарности операций, нужно просто забыть об объекте "Покупатель".
Например, Вводим три "команды"
- изменить дату рождения
- изменить имя
- изменить адрес
Которые могут вызывать скрытую "команду": изменить поле в таблице.
Принцип известный и простой - функция должна делать одну операцию и делать ее хорошо. И ничего другого она делать не должна.
Которые могут вызывать скрытую "команду": изменить поле в таблице.
и как эта команда может выглядеть?
Принцип известный и простой - функция должна делать одну операцию и делать ее хорошо.
изменить дату рождения
это очень много операций, надо отдельно:
Изменить день
Изменить месяц
Изменить год
и как эта команда может выглядеть?
Совершенно не интересует на данный момент - это особенности реализации
Ну например так
https://www.w3schools.com/sql/sql_update.asp
UPDATE Customers SET ContactName = 'Alfred Schmidt' WHERE CustomerID = 1;
это очень много операций, надо отдельно:
согласно подобным желаниям нужно не так как написано, а так:
Изменить 1й бит в дне,
Изменить 2й бит в дне,
...
и т.п. для месяца и года
А вообще, это задача для объекта "дата"
Фу-фу-фу. Плюнуть в спину, когда ничего возразить не можешь... Не уподобляйся ололёшеньке.
Я на твой вопрос ответить не могу. Не понимаю проблемы, подозреваю что слишком конкретная, шарпистикая, я с шарпом практически не работал, EF не знаю.
Чисто теоретически - в любом ОО-языке без ссылок на методы в любом месте, где нужна была бы ссылка на метод, можно использовать интерфейс.
есть энтити класс Person, хочу функцию, которой я мог бы апдейтить любое свойство объекта Person в базе данных, доступ к объектам по айди
Я не когда-то очень давно делал один пример с EF просто ради ознакомления, но что-то мне подсказывает, что все эти делегаты - просто надстройка над EF. Ну типа как Linq - надстройка над коллекциями.
В случае с Linq все это работает по одной простой причине - Linq - это просто коллекция статических функций. Там нет, ни состояния, ни взаимодействия между компонентами.
Подозреваю, что в EF тоже самое - коллекция статических функций.
Делегат как входной параметр у статической функции вполне допустим. Другое дело, что сами по себе статические функции - зачастую головная боль. Но в виде расширения какого-либо интерфейса вполне допустимо.
Как я уже говорил, я не
могу придумать пример, когда использование делегатов было бы оправдано. Как исключение можно тут указать только расширения существующих интерфейсов (типа Linq). Оспользование делегатов для уведомления других объектов - no go. Т.к. для этого надо использовать эвенты.
Вот рекомендации например:
https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/...
Никаких извращений
Там делегаты в первом же примере.
еще- изменить день недели
- изменить изменить порядковый номер дня в году
- изменить изменить порядковый номер недели в году
Самое смешное что это реальные требования потребителей.
Ну так дистанция между требованиями и реализацией может быть чуть меньше чем бесконечность, что многократно обсосано в программистком эпосе ну типа во так:
https://github.com/dotnet/runtime/blob/main/src/libraries/...
Так это имелось в виду?
public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { TSource? first = source.TryGetFirst(predicate, out bool found); if (!found) { ThrowHelper.ThrowNoMatchException(); } return first!; }
12 год - да наф нам не нужон этот ваш делегат.На всякий случай, Ололёшеньке всё равно, он у нас дурачок, по-англицки читать это не его, но вдруг кого удивило.
Во-первых, статья 1997-8 года. Не позднее. Java 1.2 не упоминается. Ну, ашипся ололёшенька. Бывает. (Статья про J++. Кто такое мелкомягкое уродство помнит?)
Во-вторых, суть статьи "нафиг усложнять VM ссылками на методы, если есть внутренние классы".
Ну и, в-третьих, ...
14 год - Джава 8 представляет лямбды и ссылки на методы."Ссылка на метод" в 8-й Яве это не "delegate". Это синтаксический сахар. Который компилятором преобразуется... во внутренний класс. Как и лямбда.
Да понятно, что из подручного мусора и костылей можно слепить что угодно, хоть небоскрёб. Мутить классы, чтобы из них использовать лишь методы, вместо того, чтобы сразу использовать лишь методы - гениальный же дизайн!
А DbSethttps://github.com/mono/entityframework/blob/master/src/En...
Можно копию кода о чём речь?
Речь об этом, на чём у вас все модели соединяются в удобоваримый контекст, а не остаются кучкой бесполезных классов.
Там делегаты в первом же примере.А разве речь о делегатах? Речь об извращениях.
Извращения это имитация ссылок на методы внутренними классами, и пятнадцать лет говорить, что нам не нужны делегаты, а потом делать их через извращения. Потому что ну уже у всех есть, включая главного конкурента.
Извращения это имитация ссылок на методы внутренними классами, и пятнадцать лет говорить, что нам не нужны делегаты, а потом делать их через извращения. Потому что ну уже у всех есть, включая главного конкурента.
Кроме тебя никто не говорил что в яве есть делегаты. Их в яве нет. В яве есть "ссылки на методы". Так до тебя дойдёт?
А хочешь кукарекать - сначала покажи мне в шарпе (главный конкурент, афигеть, а пацаны-то и не знают) замыкание по значению, а не по ссылке. Потом подумаешь, стоит ли перенимать, не понимая, принципы из других парадигм программирования. Потом разрешу тебе кукарекать.
вместо того, чтобы сразу использовать лишь методы - гениальный же дизайн!
Для объектно-ориентированного языка? Да. Ты про SmallTalk слышал? Там не то что на методы ссылаться, там код на лету менять можно. Почитай, ощути какое отсталое кю твой шарп. А потом опять немного подумай - а почему же мы все не пишем сейчас на таком прекрасном языке.
P.S. а как интересно "ссылки на методы" реализованы в Tcl... Если мелкомягкие шарписты его для себя когда-нибудь откроют, тоже начнут как не в себя тырить, не понимая что и зачем? :)
1. C# уже сильно позже Явы сделали, а потому С# во многих местах сильно лучше, поскольку по граблям уже не ходили, а все просто стырили. Ну скажем у массивов в Яве макс. размер 32 бита (2ГБ), а в C# 64 бита.
2. Надо различать язык и VM. Если в JVM чего-то нет, то значит нет, и в языке надо извращаться. В C# много чего встроили, а потому и в языке легче. Например генерики (классы с параметрами). В JVM их нет. Ну или делегаты.
3. Есть еще идеология. Многие полезные вещи считаются богохульством в ООП-религии. Ява хотела быть святее папы, а в C# все по барабану, лишь бы бабло польза была.
Кроме тебя никто не говорил что в яве есть делегаты. Их в яве нет. В яве есть "ссылки на методы". Так до тебя дойдёт?
сорри за возможно глупый вопрос: но вот это разве не делегаты?
// Function which takes in a number
// and returns half of it
Function<Integer, Double> half = a -> a /
2.0
;
// Applying the function to get the result
System.out.println(half.apply(
10
));
вот это разве не делегаты?
Может быть мы вначале начнём с определения делегатов?
https://learn.microsoft.com/en-us/dotnet/csharp/programmin...
https://www.c-sharpcorner.com/article/send-method-as-param...
сорри за возможно глупый вопрос: но вот это разве не делегаты?
Вот кстати да, как уточняет AlexNek, было бы неплохо определиться, а что мы вообще делегатами называем.
Для меня делегат это "переменная-метод". Которую можно использовать как метод.
Т.е. чтобы можно было сделать так:
Function<Integer, Double> half = a -> a /2.0; // Applying the function to get the result System.out.println(half(10));
В яве так сделать нельзя.
И этот "конструкт" должен быть "first-class citizen". Выполнять все 4 требования. В яве ссылки нa методы нельзя сравнивать. Не работает.
import java.util.function.Function; public class MyClass { public static String value(int i) { return "Value: " + i; } public static void main(String args[]) { Function<Integer, String> f1 = MyClass::value; Function<Integer, String> f2 = MyClass::value; System.out.println("Same method? : " + f1.equals(f2)); } }
Вернёт false.
Function<Integer, Double> half = a -> a /
2.0
;
компилятором превращается в
Function<Integer, Double> half = new Function<Integer, Double>() { @Override public Double apply(Integer t) { return t / 2.0; } }
Новый класс. Сделали ещё раз то же самое, получили ещё один новый класс. То же и с ссылками,
из Function<Integer, String> f1 = MyClass::value; получается
Function<Integer, String> f1 = new Function<Integer, String>() { @Override public String apply(Integer t) { return MyClass.value(t); } }
Два раза использовали ссылку, получили два класса. Сравниваешь их, а они не равны. Что правильно, это же разные классы. А вот логично было бы иметь возможность писать f1 == f2 и получать true. Если б это были и правда ссылки на методы. Вот такая фигня, малята.
Про одинаковое содержание я не заикаюсь.
Я про ссылку на одинаковый метод. x = <ссылка на метод>; y = <ссылка на тот же метод>; x == y => false. А должно быть true если б это была "настоящая ссылка на метод".
Ну, или так, сейчас со ссылками на методы такая ситуация, как будто ты делаешь
String x = "abc";
int l1 = x.length();
int l2 = x.length();
и l1 у тебя не равен l2.
P.S. к half(10) вместо half.apply(10) вопросов нет?
В чем я ошибаюсь?
Глупо будет мне с умным видом рассуждать о языке, на котором не написал ни одной строчки.
Поэтому давайте разбираться вместе.
https://learn.microsoft.com/en-us/dotnet/csharp/programmin...
https://www.c-sharpcorner.com/article/send-method-as-param...
C#
"A delegate is a type that represents references to methods with a particular parameter list and return type"
"Delegates are similar to C++ function pointers, but delegates are fully
object-oriented, and unlike C++ pointers to member functions, delegates
encapsulate both an object instance and a method."
delegate declaration
public delegate int Operation(int i, int j);
instantiate a delegate
Operation operation = (i, i1) => i + i1;
invoke
int result = operation(1, 2);
Java
"Since Java 1.8 we have the Java.util.Function interface (remember Java uses interfaces to send methods as parameters)."
Interface Function<T,R>
delegate declaration - нет
код похожий на instantiate a delegate
Function<Employee, String> f0 = (e) -> e.toString();
выполнение
String result = f0.apply(e1);
Отличия есть и довольно большие, хотя визуально ничего особенно не видно
сорри за возможно глупый вопрос: но вот это разве не делегаты?Вот кстати да, как уточняет AlexNek, было бы неплохо определиться, а что мы вообще делегатами называем.
Для меня делегат это "переменная-метод". Которую можно использовать как метод.
Т.е. чтобы можно было сделать так:
Function<Integer, Double> half = a -> a /2.0; // Applying the function to get the result System.out.println(half(10));В яве так сделать нельзя.
И этот "конструкт" должен быть "first-class citizen". Выполнять все 4 требования. В яве ссылки нa методы нельзя сравнивать. Не работает.
import java.util.function.Function; public class MyClass { public static String value(int i) { return "Value: " + i; } public static void main(String args[]) { Function<Integer, String> f1 = MyClass::value; Function<Integer, String> f2 = MyClass::value; System.out.println("Same method? : " + f1.equals(f2)); } }Вернёт false.Function<Integer, Double> half = a -> a /
2.0
;
компилятором превращается в
Function<Integer, Double> half = new Function<Integer, Double>() { @Override public Double apply(Integer t) { return t / 2.0; } }Новый класс. Сделали ещё раз то же самое, получили ещё один новый класс. То же и с ссылками,
из Function f1 = MyClass::value; получается
Function<Integer, String> f1 = new Function<Integer, String>() { @Override public String apply(Integer t) { return MyClass.value(t); } }Два раза использовали ссылку, получили два класса. Сравниваешь их, а они не равны. Что правильно, это же разные классы. А вот логично было бы иметь возможность писать f1 == f2 и получать true. Если б это были и правда ссылки на методы. Вот такая фигня, малята.
Толчея воды в ступе. Спор даже не о словах, а о буквах. Единственный вывод, что я делаю из этой простыни: Джава говно, Сишарп - конфетка (по сравнению с Джавой).
что вы мне тут пытаетесь доказать? Что в с# Что в яве я могу определить переменную или свойство с определённым входным и выходным типом, а затем в коде переопределять ее как мне заблагорассудится.
Вы можете хоть из штанов выпрыгнуть, но это одно и то же.
что вы мне тут пытаетесь доказать?
Абсолютно ничего. Я предложил разбираться вместе и привел мои рассуждения. Вы с ними несогласны и приводите свои - ну так это замечательно. Через какое то время можно будет найти и точки соприкосновения. Ну или точно определится с разногласиями.
я могу определить переменную или свойство с определённым входным и выходным типом, а затем в коде переопределять ее как мне заблагорассудится.
Если подходить более строго, то переменная может иметь только лишь значение и тип, но да понятно, что имелось в виду.
Однако для меня это определение - всего лишь ссылка на метод. Типа как в Си. МС не трактует делегаты подобным образом. (A delegate is a type that represents references to methods with a particular parameter list and return type. Delegates are an object-oriented, type safe, and secure type that safely encapsulates a method)
Вот еще определение нашел: The delegate is a reference type data type that defines the method signature. You can define variables of delegate, just like other data type, that can refer to any method with the same signature as the delegate.
Насколько я понял, в Яве подобного определения нет.
И я совсем не уверен, что в Яве возможно что то подобное
public delegate void MyDelegate(); MyDelegate delg = () => Console.WriteLine("Test"); delg();
что вы мне тут пытаетесь доказать? Что в с# Что в яве я могу определить переменную или свойство с определённым входным и выходным типом, а затем в коде переопределять ее как мне заблагорассудится.
Вы можете хоть из штанов выпрыгнуть, но это одно и то же.
Они пытаются доказать, что если в Джаве реализовано по-другому, то это не делегаты, как в Шарпе, а своя какая-то неведомая херня. Можно было бы сказать, что в Шарпе - ссылки на методы. Но они и тут бы возбудились - нет, в Шарпе делегаты! Спорят о словах и прочих неважных вещах, лишь бы увести в сторону от главного - в Джаве это реализовано хуже и костыльнее, не такое широкое применение имеет и не так хорошо интегнировано в язык и фреймворк.
И я совсем не уверен, что в Яве возможно что то подобное
public delegate void MyDelegate(); MyDelegate delg = () => Console.WriteLine("Test"); delg();
Примерно так же, кроме последней строчки. В яве ссылка не метод превращается в объект. И пока что синтаксический сахар, чтобы вызвать deleg() не прикрутили. Runnable существующий тип, можно определить свой. Просто интерфейс с одним методом.
Runnable delg = () -> System.out.println("Print"); delg.run();
А как в шарпе можно присвоить delegate-у существующий метод класса? MyDelegate delg = <метод printX() объекта x1 типа X>;
Спорят о словах и прочих неважных вещах, лишь бы увести в сторону от главного...
Абсолютно согласен с вами, коллега, надо смотреть ширше и глыбже! Неважно на каком языке реализовано - главное результат!
Надо смотреть на уровень зарплаты, у кого зарплата больше - тот и прав! Практика является важным критерием истинности!
Кто пьёт смузи, у кого нестыдная машина, кто работает начальником - тот и прав! Эта истина проста, но не всем доступна!
Примерно так же, кроме последней строчки...А как в шарпе
Судя пот ответу вы считает, что я тоже бросаю камни в Яву. Абсолютно не так. Я просто пытаюсь найти отличия.
И в данном случае опирался на это
https://docs.oracle.com/javase/8/docs/api/java/util/functi...
Про Runnable там не было. Интересно как с различными количеством параметров происходит?
Но опять таки, я не вижу определения типа, так как используются только существующие (видимо) интерфейсы.
в Джаве это реализовано хуже и костыльнее
А можно уточнить какой у вас опыт разработки приложений на Яве?
Могу сразу сказать, что у меня нулевой. Но если в каком то языке мне что то не нравится - это совсем не значит что язык из-за этого полное дёрьмо.
пытаются доказать
Это просто размышления вслух, как способ изучения материала.
Что то кому то доказывать, практически бесполезная трата времени. А может и того хуже https://ru.wikipedia.org/wiki/Рели�%...
И я совсем не уверен, что в Яве возможно что то подобноеПримерно так же, кроме последней строчки. В яве ссылка не метод превращается в объект. И пока что синтаксический сахар, чтобы вызвать deleg() не прикрутили. Runnable существующий тип, можно определить свой. Просто интерфейс с одним методом.public delegate void MyDelegate(); MyDelegate delg = () => Console.WriteLine("Test"); delg();
Runnable delg = () -> System.out.println("Print"); delg.run();А как в шарпе можно присвоить delegate-у существующий метод класса? MyDelegate delg = <метод printX() объекта x1 типа X>;
Можно вывести тип делегата автоматически (начиная с 10 версии языка), если он совпадает с одним из Func или Action (до 16 параметров в каждом). Как раньше было сказано, в Дотнете определены Func или Action с числом обобщённых параметров до 16 (плюс возврат для Func), что позволяет покрыть практически все варианты функций. Тут в меню слева видно. Это позволяет работать фиче автоматического выведения типа делегата. Но если у вас свой тип, повторяющий один из уже готовых Func или Action - может не сработать, или приведёт к одному из Func-Action (тут я точно не знаю - не использовал). Посему лучше использовать уже готовый тип, если он совпадает с нужной вам сигнатурой по входящим параметрам и возврату, чтобы все выведения работали автоматически. Те, кто нарушают конвенции и изобретают велосипеды - да, должны страдать.
Так что объявлять свои типы делегатов для типичных методов - бесполезное занятие. Разве что кто-то хочет именно через имя типа делегата разъяснить, для чего он служит. Но это лишнее. В Дотнете существуют старые делегаты, которые ввели до появления пачек Action и Func - их оставили для совместимости. Но фактически Predicate это один из вариантов Func.
Ещё тут разъяснено, и как это делалось до версии 10.
Да, кстати, что там в Джаве в качестве аналога деревьев выражений?
"Most times you're going to want Func or Action if all that needs to happen is to run some code. You need Expression when the code needs to be analyzed, serialized, or optimized before it is run. Expression is for thinking about code, Func/Action is for running it."
Я уже не говорю про динамический LINQ.
Судя пот ответу вы считает, что я тоже бросаю камни в Яву. Абсолютно не так. Я просто пытаюсь найти отличия.
Нет, мне просто интересно как в шарпе реализовали именно ссылки на методы, а не присваивание "имён" лямбдам. Я с этим в шарпе не сталкивался.
Про Runnable там не было. Интересно как с различными количеством параметров происходит?
В яве сделали через "функциональные интерфейсы". Любой интерфейс с одним методом считается "функциональным", т.е. может описывать тип функции (метода).
Runnable старый интерфейс, который был и до 8-й явы, и не лежит в java.util.function. Но так как у него один метод, то и он стал "фунциональным" :) И он прям подошёл для твоего примера, потому что параметров нет и ничего не возвращает.
Фишка в том, что любой метод класса или лямбду можно определить типом функционального интерфейса у которого единственный метод имеет те же параметры (количество и тип) и тот же тип результата (ну, про наследование и приведение типов не забываем) что и наш метод / лямбда. В примере, как add: два инта и возвращает инт.
public interface MyMethod { int add(int a, int b);} // Не функциональный! больше одного метода public interfce TooManyMethods { int add(int a, int b); int multiply(int a, int b); } MyMethod m = (a, b) -> a + b; // маловато параметеров, ошибка будет MyMethod wrong = a -> a + 10;
как-то так
да вроде то же самое есть
private static Function<Integer, Integer> multiply = x -> x * 2;
private static Function<Integer, Integer> add = x -> x + 2;
private static Function<Integer, Unit> logOutput = x -> {
logger.info("Data:" + x);
return Unit.unit();
};
public static Unit execute(Integer input) {
Function<Integer, Unit> pipeline = multiply
.andThen(add)
.andThen(logOutput);
return pipeline.apply(input);
}
да вроде то же самое есть
<code> private static Function<Integer, Integer> multiply = x -> x * 2; private static Function<Integer, Integer> add = x -> x + 2; private static Function<Integer, Unit> logOutput = x -> { logger.info("Data:" + x); return Unit.unit(); }; public static Unit execute(Integer input) { Function<Integer, Unit> pipeline = multiply .andThen(add) .andThen(logOutput); return pipeline.apply(input); } </code>
Это больше похоже на Select и SelectMany - просто пачка расширяющих методов с делегатами в качестве параметров, применяемых ко входным данным и результатам. А я спросил про деревья выражений - сериализация делегатов и функций, представление их в виде данных.
Вобщем, я поискал - нет такого в Джаве из коробки. Есть какие-то сторонние либы, разрабатываемые энтузиастами, типа JaQue. Это не сравнимо с Дотнетом и Шарпом, где подобные фичи разрабатываются, внедряются во фреймворк и поддерживаются на системном уровне самой компанией-разработчиком языка и фреймворка. В Дажве и большинстве других языков без крупного хозяина всегда такие проблемы - их экосистемы представляют из себя конструктор "сделай сам" - т.е. практически отсутствуют. Надо писать под десктоп? - Ищи гуёвую либу под Джаву. Надо под веб? - Ищи гуёвую либу для веба. Надо трёхмерную графику? - Ищи джавовый движок. И вот часто у Джавы и других языков либо нет нифига для этого, либо что-то стороннее, с поддержкой мелкой фирмочки или вообще тремя с половиной энтузиастами. Хочешь комплексное решение "всё из коробки, подогнанное"? - Иди к Майкрософт. Да, у них есть проблемы. Но у других их ещё больше. Что-то подобное есть лишь у Эппл. Но хуже, мельче, меньший охват (нет своей СУБД, например), и нужно менять ориентацию (в переносном смысле).
Как про другое, если это оно и есть?
https://docs.oracle.com/javase/8/docs/api/java/util/functi...
Написать можно что угодно на чём угодно. Только на одном это будет легко и приятно, а на другом нет. Вспоминаем.
Нет, мне просто интересно как в шарпе реализовали именно ссылки на методы
Ну тут вроде достаточно много
https://www.tutorialsteacher.com/csharp/csharp-delegates
Если недостаточно, опишите подробнее, что именно интересует.
Есть подозрения, что начнётся новый вой, что в этом хх языке и Multicast Delegate нету
Ну тут вроде достаточно много
https://www.tutorialsteacher.com/csharp/csharp-delegates
Только потом читатели букварей забывают забыть все эти MyDelegate(string msg), и начать пользоваться обычными Action и Func. Так и продолжают клепать свои однотипные делегаты на каждый чих.
в этом хх языке и Multicast Delegate нету
Я уже привык, что многое в Джаве, включая делегаты - кривое-косое-урезанное. После Сишарпа - будто переехал из своего дома в общагу. Как правильно отмечают в беседах на том же Stackoverflow, создатели Джава слишком ограничили себя "чистым ООП", загнали в сами себе же созданные рамки ради идеологии, принеся в жертву реальные потребности. Шарп оказался гибче и этим лучше. Да плюс возник попозже, учтя ошибки Джавы. "Что отвердело, то не победит."
Ну тут вроде достаточно много
https://www.tutorialsteacher.com/csharp/csharp-delegate
Во. Вот это меня интересует: MyDelegate del = MethodA;
Если я два делегейта сделаю
MyDelegate del1 = MethodA;
MyDelegate del2 = MethodA;
del1 будет равен del2? del1 == del2, или del1.Equals(del2)?
Мне можно, т.к. на самом деле я ламер.
Глянул получше - это что-то типа Enumerable? Можно бесконечно цеплять фукнции к последовательностям, которые что-то делают с элементами этих последовательностей?
Просто в Select то же самое - это расширение Enumerable, позволяющее сразу задать несколько действий над элементами последовательности через параметры-делегаты.
del1 будет равен del2?
Никогда не интересовало, но по идее должны быть равны.
И таки да:
https://dotnetfiddle.net/9qRfq2 интересно еще View IL глянуть
Никогда не интересовало, но по идее должны быть равны. И таки да
Ну вот. Поэтому (для меня) в шарпе делегейты есть, а в яве - нет. Если определять (по-моему неправильно) делегейт как "возможность передать метод как параметр" тогда они есть и в шарпе и в яве. Причём с самой первой версии :)
P.S. Но и тот и другой близко не функциональные языки с выводом типов (type inference) вроде ML или хаскеля.
В Яву потихоньку подвозят Сишарп 5-7-летней давности.
Implicitly Declared Classes and Instance Main Methods (Second Preview) (JEP 463)
Мне ненравится как сделали этот JEP. Есть проблема-многословный синтаксис, лишние абстракции которые как выяснилось не всегда нужны. Что мы сделаем, исправим это в языке? Нет, введем дополнительный граничный случай для начинающих с неявно объявленными классами, которые как потом выснится больше нигде работать небудут.
В Яве через эти внутренние классы вообще все фичи вводят?
Новая часть кода сделана по ЧиА, а старая постепенно переносится из дремучего легаси в новую парадигму. Да, получилось много классов, но они маленькие, сконцентрированные на своей задаче, разбитые по слоям. Но в чём проблема?
Проблема в том, что управлять кучей мелкотни, разбросанной по слоям, не особо проще, чем монолитом. Монолит можно весь выбросить и переписать, или хотя бы его большие части. А у мелкотни обвязка по связности между собой зачастую больше самой функциональности, закладываемой в эту мелкотню. Т.е. у нас поддерживающая инфрасруктура больше, чем основное производство. Долго возводим леса, кантуем оснастку вокруг, огораживаем, убивая дни на всё это. А потом приходит Петрович и за одну минуту в нужном месте один раз бьёт кувалдой. После чего всё несколько дней разбираем. Примерная аналогия из строительства.
Вообще, всё это сделано для якобы аджайла и continuous integration. Но зачастую проекты как один раз написаны, так почти без существенных доработок и существуют годами. После чего их в значительной части или полностью переписывают. Раз в 5-10 лет. Получается просто последовательность переписываемых почти-монолитов. И такая модель в некоторых случаях более уместна. Проблема всяких аджайл-фанатиков и прочих солидистов в том, что они пихают своё видение во все щели, даже где оно нафиг не сдалось.
без ЧиА в легаси это большие классы на несколько сотен строк, а в новом коде это много классов до сотни строк каждый
Блин, чел хоть раз открывал исходники больших библиотек? Там некоторые классы на тыщи строк. Вот проще и удобнее в некоторых случаях сделать класс на тыщи строк - его так и делают. А не следуют тупым и слепым догмам "классы должны быть маленькими". В куче связанных мелочей зачастую очень трудно составить весь путь потока информации от скажем нажатия на кнопку до получения результата. Там всё проходит через десять слоёв, 20 классов и пачку конвертаций. Задолбаешься прыгать по этим мелким классам, отслеживая стеки вызовов.
Видно, что народ вся эта хитромудрая хрень уже достала.совсем не обязательно, то что вы видите в своем микроскопе должны видеть и другие.
Что-то вы подзадолбали со своим аналогом divercity. Показываешь круглый оранжевый апельсин, а тебе в ответ лекцию, что для некоторых апельсин не круглый, и даже не оранжевый. И есть люди с дальтонизмом, и их может оскорбить или обидеть вот это навязывание, что апельсины оранжевые. Вполне возможно, что они серые, просто у вас микроскоп другой. И прочая шняга в таком духе.
Но зачастую проекты как один раз написаны, так почти без существенных доработок и существуют годами.имею большое количество совершенно обратных примеров, но не хочу утверждать, что все были написаны хорошо.
Что было бы с вами, если бы вас родили не монолитом? Или пришол бы такой дядя с ножом, и предложил бы вам превратиться в кучку микросервисов с органами и частями тела по пакетам? Не везде микросервисы полезны - где-то рулят монолиты. ))
Показываешь круглый оранжевый апельсин
А не приходит другое сравнение?
Что все говорят, да у тебя в руке мячик и только тебе видится апельсин
Что-то вы подзадолбали со своим аналогом divercity.
отчего то вы видите всё в другом свете.
Речь всего лишь о том, что не следует везде кричать - я имею мнение и оно единственно правильное. Всё остальное чушь собачья.
2022!
https://www.rbc.ru/society/02/08/2022/62e8e09f9a794727b478...
Да пациенту просто скучно. Он и развлекается как может. А может он плоховато.
Кто-нибудь! Заберите его во Флориду! Посадите в клетку, будете людям за деньги показывать. Только клeтка чтоб на берегу моря (или океана)! win-win
Заметьте, я просто кинул ссылки пару раз на мысли других людей. А то вы тут могли подумать, что лишь я что-то "обсираю". А вот люди тоже недовольны, и их немало.
Что, шатается земля под ногами? Чувствуете неуверенность в казавшихся нерушими догматах? ))
Речь всего лишь о том, что не следует везде кричать - я имею мнение и оно единственно правильное. Всё остальное чушь собачья.
2022!
https://www.rbc.ru/society/02/08/2022/62e8e09f9a794727b478...
В клетку нельзя, на доске кататься не сможет.
А как ещё зрителей защитить? Он же их заплюёт: и прибой звучит неправильно, и цвет у воды не как на картинке, и пальмы растут не те и не там. На доске кататься только за хорошее поведение :) Будет как отец Фёдор на скале:
"Спустилась быстрая ночь. В кромешной тьме и в адском гуле под самым облаком дрожал и плакал отец Федор. Ему уже не нужны были земные сокровища. Он хотел только одного – вниз, на землю. Ночью он ревел так, что временами заглушал Терек, а утром подкрепился любительской колбасой с хлебом и сатанински хохотал над пробегавшими внизу автомобилями. Остаток дня он провел в созерцании гор и небесного светила – солнца. Ночью он увидел царицу Тамару."