Deutsch

C# - pattern matching - many discards

4690  1 2 3 4 5 6 7 8 9 10 все
alex445 коренной житель20.02.24 16:20
20.02.24 16:20 
Последний раз изменено 20.02.24 16:36 (alex445)

Вопрос про оформление и красивости. И можно ли вообще так написать.


Вобщем, понадобилось проверить объект на кучку разномастных условий. Например, на налл весь объект, на значение одно из свойств, если объект не налл, и вернуть что-то другое, если какие-то ещё условия. И хочу спросить, как удобнее сделать, чтобы не писать простыную из вложенных ифов. Пусть мы получили где-то объект 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;
}


Ситуация с ифами ухудшается, если количество проверок увеличивается. А в сопоставлениях с образцом - просто добавляется одна строчка на проверку.

#1 
alex445 коренной житель20.02.24 16:40
NEW 20.02.24 16:40 
в ответ alex445 20.02.24 16:20, Последний раз изменено 20.02.24 16:42 (alex445)

Древовидная структура ифов легко трансформируется в линейную структуру сопоставлений, просто порядок соблюдать надо - сначала одну ветку ифов последовательно в сопоставлениях пишем, потом другую. Разве что если условий становится больше десятка, как и вложенностей - по 3-4 и больше. Но и тогда на мой взгляд сопоставления лучше - они хотя бы на экран влезут, а дерево ифов явно расползётся куда дальше. Ну и всегда можно отделить группы кейсов в сопоставлениях форматированием - добавить между ними пустую строчку, например. А в ифах уже и так места нет, так ещё их удлинять.

#2 
alex445 коренной житель20.02.24 16:44
NEW 20.02.24 16:44 
в ответ alex445 20.02.24 16:20
var result = row.Age switch
{
    _ when row == null => MyEnum.NotAllowed,
    > 100 => MyEnum.Died,
    _ => MyEnum.StillAlive,
};

Не уверен, но тут, по-моему, может NullReferenceException вылететь уже на row.Age, если row налл. Ну можно тогда так написать row?.Age.

#3 
7495 старожил20.02.24 17:35
7495
NEW 20.02.24 17:35 
в ответ alex445 20.02.24 16:20
var result


Вот 3 варианта получить "result" на чистом сишарповском языке. Результат везде одинаков.

Вопросы и Ответы - Программируем калькулятор пособий для беженцев вместе.
#4 
AlexNek патриот20.02.24 19:51
AlexNek
NEW 20.02.24 19:51 
в ответ alex445 20.02.24 16:40

Похоже мы опять изобретаем очередной велосипед.

Этих реализаций дофига, например

https://docs.fluentvalidation.net/en/latest/start.html

https://github.com/Blazored/FluentValidation

https://code-maze.com/complex-model-validation-in-blazor/


и свитч и ифы не подходят, если уж свое сильно хочется.

#5 
AlexNek патриот20.02.24 19:56
AlexNek
alex445 коренной житель21.02.24 00:00
NEW 21.02.24 00:00 
в ответ AlexNek 20.02.24 19:51

Валидаторы тут не причём. Я спросил, как насчёт такой конструкции с образцами, где несколько дискардов идут - нормально выглядит, или вы знаете способ лучше? Объект с его полями тут лишь для примера, и валидация ему не нужна.

#7 
AlexNek патриот21.02.24 18:04
AlexNek
NEW 21.02.24 18:04 
в ответ alex445 21.02.24 00:00
Я спросил, как насчёт такой конструкции с образцами, где несколько дискардов идут - нормально выглядит

Просто ужасно, даже и без дискардов


Вариант fluent validation намного лучше

#8 
Отпускник завсегдатай21.02.24 18:57
NEW 21.02.24 18:57 
в ответ AlexNek 21.02.24 18:04

приведи свой вариант решения.

#9 
AlexNek патриот21.02.24 19:29
AlexNek
NEW 21.02.24 19:29 
в ответ Отпускник 21.02.24 18:57, Последний раз изменено 21.02.24 19:45 (AlexNek)

ну так написал же... Пишешь просто набор правил

    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");;

#10 
alex445 коренной житель21.02.24 19:41
NEW 21.02.24 19:41 
в ответ AlexNek 21.02.24 19:29, Последний раз изменено 21.02.24 19:44 (alex445)
ну так написал же... Пишешь просто набор правил

Вы чтобы в туалет сходить, сначала строите маленький заводик по производству туалетной бумаги? А если понос? ))


Дискарды юзаю только потому, что в условиях должен быть тип входного для свича параметра.

Можно бы было произвольные условия проверки писать - обошёлся бы без этого костыля. Но произвольно в паттерн матчинг пока не завезли.

#11 
AlexNek патриот21.02.24 19:46
AlexNek
NEW 21.02.24 19:46 
в ответ alex445 21.02.24 19:41

Во первых, всё уже написано,

во вторых, был вопрос как нравится

#12 
Отпускник завсегдатай21.02.24 19:55
NEW 21.02.24 19:55 
в ответ AlexNek 21.02.24 19:29

причем тут твои правила? Напиши эквивалент вот этому коду:

var result = row.Age switch
{
    _ when row == null => MyEnum.NotAllowed,
    > 100 => MyEnum.Died,
    _ => MyEnum.StillAlive,
};
#13 
alex445 коренной житель21.02.24 20:30
NEW 21.02.24 20:30 
в ответ AlexNek 21.02.24 19:46

Во первых, всё уже написано,

во вторых, был вопрос как нравится

Вы не поняли - проверки могут быть где угодно, а не лишь внутри ваших безнес-правил. И там не обязательно объект с полями, а может быть просто скажем строка. Проверяем её на налл, длину, наличие такого или иного символа или их сочетания... Ну понятно, вы и тут правила свои напишете - в виде расширения класса строк. Любой лапшекод, лишь бы паттерн матчинг не использовать )))

#14 
NightWatch коренной житель21.02.24 22:59
NightWatch
NEW 21.02.24 22:59 
в ответ alex445 20.02.24 16:20
Ситуация с ифами ухудшается, если количество проверок увеличивается. А в сопоставлениях с образцом - просто добавляется одна строчка на проверку.

Перепиши if так, чтобы была одна строчка на проверку.

MyEnum result;
if (row == null) result = MyEnum.NotAllowed;
else if (row.Age > 100) result = MyEnum.Died;
else result = MyEnum.StillAlive;
#15 
alex445 коренной житель22.02.24 01:17
NEW 22.02.24 01:17 
в ответ NightWatch 21.02.24 22:59, Последний раз изменено 22.02.24 01:28 (alex445)

Тоже можно. Но текста куда больше из-за засилья словесных операторов и присвоения в каждой строчке.

С другой стороны, в моём варианте используются ненужные мне дискарды в качестве костылей. В идеале должно быть [условие] => [возврат].


Вот красным отметил информационный мусор в моём и вашем вариантах


#16 
Murr патриот22.02.24 01:57
Murr
NEW 22.02.24 01:57 
в ответ alex445 22.02.24 01:17

В идеале должно быть [условие] => [возврат].

------

Об этом мы спорили во времена Аксесс 2.

есть плюсы... есть и минусы...

Самый простой вопрос - у тебя два и более различаемых условий независящих от переменной в свитче - что писать будешь?

Чуть более сложный - что с производительностью при большом числе правил?

#17 
alex445 коренной житель22.02.24 13:58
NEW 22.02.24 13:58 
в ответ Murr 22.02.24 01:57, Последний раз изменено 22.02.24 14:04 (alex445)
Самый простой вопрос - у тебя два и более различаемых условий независящих от переменной в свитче - что писать будешь?

Свободно можно использовать. Как я выше написал - сначала нужен костыль-значение с типом переменной, или дискард, а затем "when" и далее любые проверки с любыми переменными из контекста, в котором находится данный свитч. Разве что результат такой проверки должен быть булевым.


Про производительность не знаю. По-моему, раз все эти проверки условий (if-else, switch) взаимозаменяемы, то они генерятся в одинаковый исполняемый код. Их разные записи - лишь для удобства использования в разных случаях. А значит вопрос производительности того или другого высокоуровневого кода не стоит - стоит вопрос производительности итогового исполняемого кода. Ну, думаю, там какую-нибудь хеш-таблицу замутили на все обозначенные программистом комбинации условий, так что при проходе по ветке условий сразу нужная имплементация выполняется.

#18 
Murr патриот22.02.24 14:12
Murr
NEW 22.02.24 14:12 
в ответ alex445 22.02.24 13:58

то они генерятся в одинаковый исполняемый код.

------

не обязательно...

#19 
AlexNek патриот22.02.24 19:26
AlexNek
NEW 22.02.24 19:26 
в ответ alex445 21.02.24 20:30
проверки могут быть где угодно

ну тогда и ничего обсуждать о подобной программе, делайте как нравится и будет счастливы.


Я бы еще посчитал, что нам потребуется для предыдущего кода во всех местах.


вы и тут правила свои напишете

единого решения для всех случаев жизни не существует

#20 
1 2 3 4 5 6 7 8 9 10 все