Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

C# - У чего приоритет больше - у операторов или паттернов?

1042  1 2 3 4 все
alex445 коренной житель21.11.22 15:23
21.11.22 15:23 
Последний раз изменено 21.11.22 15:24 (alex445)

Например, такое выражение


if (enumValue == MyEnum.One || enumValue == MyEnum.Two || enumValue == MyEnum.Three)


можно записать так - гораздо короче и понятнее


if (enumValue is MyEnum.One or MyEnum.Two or MyEnum.Three)


А что если в if проверяется ещё что-то? Например


if (obj != null || enumValue == MyEnum.One || enumValue == MyEnum.Two || enumValue == MyEnum.Three)


Тогда можно записать


if (obj != null || enumValue is MyEnum.One or MyEnum.Two or MyEnum.Three)


Но тогда непонятно, что вперёд выполняется. Где в спецификации языка или в МСДН написано, что операторы имеют бОльший приоритет, чем паттерны?


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

#1 
alex445 коренной житель21.11.22 15:34
NEW 21.11.22 15:34 
в ответ alex445 21.11.22 15:23

Нашёл только это пока

https://learn.microsoft.com/en-us/dotnet/csharp/language-r...


Но тут про приоритет лишь паттернов, но не паттернов и операторов.

#2 
Срыв покровов патриот21.11.22 19:22
NEW 21.11.22 19:22 
в ответ alex445 21.11.22 15:23, Последний раз изменено 21.11.22 19:23 (Срыв покровов)

ну вроде ж очевидно, что сначала выполняется is..or, а потом ||
Или твой вопрос был не в этом?


Для твоего случая можно написать что-нибудь типа этого


int number = 5;
bool res = number.In(1,2,3,4);
 
public static bool In<T>(this T item, params T[] items)
{
    if (items == null)
       throw new ArgumentNullException("items");

    return items.Contains(item);
}
#3 
alex445 коренной житель21.11.22 19:50
NEW 21.11.22 19:50 
в ответ Срыв покровов 21.11.22 19:22

Ну, для меня было не очевидно. Вообще, все "очевидности" должны быть явно прописаны - вот я и спрашивал, может кто знает, где точно указано, что операторы вперёд паттернов.


Да для таких вещей не надо ничего расширяющего писать - всё есть. Если руками каждое отдельное число забивать, то проще массив через скобочки. Если сгенерить последовательность подряд идущих чисел, то проще Enumerable.Range или что-то такое. И потом IEnumerable.Contains. У меня вариант, когда надо проверить на равенство двум-трём значениям. Обычно это для перечислений или чего подобного с небольшим количеством возможных значений. Просто неохото писать портянку || или && с повторением проверяемого значения.


Вобщем, уже понял, что проще делать типа такого


A is B or C or D

или для понятливости

A is (B or C or D)

#4 
  simplename знакомое лицо21.11.22 20:24
NEW 21.11.22 20:24 
в ответ alex445 21.11.22 15:23

А ты поломай голову и напиши тест, который тебе это покажет. Ставлю на то, что не напишешь.

#5 
Срыв покровов патриот21.11.22 21:19
NEW 21.11.22 21:19 
в ответ alex445 21.11.22 19:50
Да для таких вещей не надо ничего расширяющего писать - всё есть. Если руками каждое отдельное число забивать, то проще массив через скобочки. Если сгенерить последовательность подряд идущих чисел, то проще Enumerable.Range или что-то такое. И потом IEnumerable.Contains.

По мне так это гораздо более громоздко чем в моём примере.

#6 
alex445 коренной житель21.11.22 22:47
NEW 21.11.22 22:47 
в ответ simplename 21.11.22 20:24

Всё написано и проверено уже - работает.

#7 
Программист коренной житель22.11.22 10:53
NEW 22.11.22 10:53 
в ответ Срыв покровов 21.11.22 19:22
ну вроде ж очевидно, что сначала выполняется is..or, а потом ||

Почему очевидно?


if (obj != null || enumValue is MyEnum.One or MyEnum.Two or MyEnum.Three)

ЕМНИП вычисление выражений идет слева направо, так что сначала будет вычислено "obj != null" и если это выражение true, то все остальное в принципе не должно вычисляться.

#8 
Программист коренной житель22.11.22 10:59
NEW 22.11.22 10:59 
в ответ alex445 21.11.22 19:50
Просто неохото писать портянку || или && с повторением проверяемого значения.
Вобщем, уже понял, что проще делать типа такого
A is B or C or D
или для понятливости
A is (B or C or D)


Для понятливости надо избегать смешивания разных видов записей.

И чем проще выражение внутри if'а, тем лучше.


В твоем случае лучше было бы записать так:

bool allowedValue = enumValue is MyEnum.One or MyEnum.Two or MyEnum.Three;
if (obj != null || allowedValue)




#9 
Срыв покровов патриот22.11.22 14:13
NEW 22.11.22 14:13 
в ответ Программист 22.11.22 10:53
ЕМНИП вычисление выражений идет слева направо, так что сначала будет вычислено "obj != null" и если это выражение true, то все остальное в принципе не должно вычисляться.

Ну поэтому я и переспросил, как по-другому компилятор это может понять.

#10 
alex445 коренной житель22.11.22 15:12
NEW 22.11.22 15:12 
в ответ Программист 22.11.22 10:59, Последний раз изменено 22.11.22 15:15 (alex445)
Просто неохото писать портянку || или && с повторением проверяемого значения.
Вобщем, уже понял, что проще делать типа такого
A is B or C or D
или для понятливости
A is (B or C or D)


Для понятливости надо избегать смешивания разных видов записей.
И чем проще выражение внутри if'а, тем лучше.


В твоем случае лучше было бы записать так:


bool allowedValue = enumValue is MyEnum.One or MyEnum.Two or MyEnum.Three;
if (obj != null || allowedValue)

Я бы избежал, но в одном паттерне, насколько я понял, нельзя использовать, скажем так, разные данные. Я попробовал сделать заменить это


if (obj != null || (enumValue is MyEnum.One or MyEnum.Two or MyEnum.Three))


на это


if (obj != null or (enumValue is MyEnum.One or MyEnum.Two or MyEnum.Three))


или даже так


if (obj is not null or

(enumValue is (MyEnum.One or MyEnum.Two or MyEnum.Three)))


- так нельзя. Ругается что-то типа, что obj и enumValue разные данные и их нельзя в одном паттерне использовать. Хотя по логике, оба паттерна "возвращают" bool - потому почему бы не использовать? Основная идея была - не повторять для каждого сравнения enumValue.


Паттерны вообще что-нибудь "возвращают"?

#11 
Murr патриот22.11.22 15:24
Murr
NEW 22.11.22 15:24 
в ответ alex445 21.11.22 19:50

Просто неохото писать портянку

-----

А кто тебя заставляет писать портянку?

#12 
alex445 коренной житель22.11.22 15:34
NEW 22.11.22 15:34 
в ответ Murr 22.11.22 15:24

Да понятно, что можно доп. переменных навводить. Но ещё охота, чтобы было красиво.

#13 
Murr патриот22.11.22 15:40
Murr
NEW 22.11.22 15:40 
в ответ alex445 22.11.22 15:34

доп. переменных навводить

-----

Нах?

У тебя список чего-то и переменная - делаешь список статическим для и проверяешь вхождение.

Ну либо два списка и ищешь один в другом...

#14 
alex445 коренной житель22.11.22 19:29
NEW 22.11.22 19:29 
в ответ Murr 22.11.22 15:40

Немного не так. Есть пара переменных, значения которых надо проверить. Одну - на null, вторую - на равенство некоторым значениям из перечисления. По сути, это либо портянка if-else, либо портянка из логических операторов с кучей скобок. Паттерновые конструкции позволяют сделать эти портянки поменьше чисто за счёт менее многословного синтаксиса. Только и всего. Ну а дополнительные переменные просто сделают портянку более читаемой, но всё равно оставят портянкой. Можно ещё со свичём поиграться и кортежами - все возможные комбинации загнать в кортежи и сделать их кейсами свича. Но при числе комбинаций больше 3 это уже само по себе та ещё портянка.


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

#15 
  simplename знакомое лицо22.11.22 20:51
NEW 22.11.22 20:51 
в ответ alex445 21.11.22 22:47

любишь "код с сахаром" (syntax shugar)?


почитай еще здесь, может будет интересно.


https://blog.ndepend.com/csharp9-new-keywords-for-pattern-...


но если перфоманс не критичен, то, конечно, следует выбрать более читабельный вариант. или что диктуют "правила кодирования", примятые в данной конторе (если имеются).

#16 
alex445 коренной житель22.11.22 21:40
NEW 22.11.22 21:40 
в ответ alex445 22.11.22 19:29, Последний раз изменено 22.11.22 21:41 (alex445)

Щас попробовал поэкспериментировать со свичом и кортежами - плохо получается. Т.е. типа


switch (a, b, c)

(,,) => true,

(,,) => true,

(,,) => true,

_ => false,


где в скобках возможные сочетания переменных а, b, с. Но проблема возникает, если одна из переменных nullable, как я раньше писал в примерах, и нужно проверить, что она не null. Вот null можно, а литерала "not null" нет. Приходится тогда всю эту "таблицу" кортежей инвертировать и перебирать варианты с возвратом false, а всё остальное - true. Но если вариантов с false в разы больше, то получается совсем большая портянка. А вот паттерны "is, is not, and, or" делают это всё короче - буквально в одну строчку.

#17 
alex445 коренной житель22.11.22 21:47
NEW 22.11.22 21:47 
в ответ simplename 22.11.22 20:51

Ну там по сути перечисляется то, что у же давно в МСДН описано. Только добавить, как я выше написал, что новые паттерны не только заменяют некоторые операторы, но и предоставляют доступ именно к неперегруженной логике (в отличие от операторов, которые могут быть перегружены).


Ну и мой пример приведён:


A better example is the expression if(x is 1 or 2 or 3). It is more compact than if((x==1) || (x==2) || (x==3)) and makes sense.
#18 
alex445 коренной житель28.11.22 16:55
NEW 28.11.22 16:55 
в ответ alex445 22.11.22 21:47

Вобщем, эта штука удобна в том числе, когда надо проверить переменную на соответствие некоторым значениям перечисления.


Если много разных кейсов обработки переменной на разные значения перечисления - то лучше выражение switch -

weekDay switch =>

{

DaysOfWeek.Monday => ...,

DaysOfWeek.Tuesday => ...,

DaysOfWeek.Wednesday => ...,

...

_ =>

};


Если один кейс на меньшинство значений перечисления, то лучше паттерн "is (or...)" -

bool isHoliday = weekDay is (DaysOfWeek.Saturday or DaysOfWeek.Sunday);


Если один кейс на большинство значений перечисления, то лучше паттерн "is not (or...)" -

bool isWorkingDay = weekDay is not (DaysOfWeek.Saturday or DaysOfWeek.Sunday);


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

#19 
Срыв покровов патриот28.11.22 23:37
NEW 28.11.22 23:37 
в ответ alex445 28.11.22 16:55

хз, один раз написал свою функцию In и не нарадуюсь

#20 
1 2 3 4 все