{ }
От: BlackEric http://black-eric.lj.ru
Дата: 26.10.23 15:57
Оценка:
Я сейчас глупость спрошу, но зачем в коде

if (stage() is { } stages)

{ }, что они означают?

stage возвращает List<Stage>. Stages имеет этот же тип.
https://github.com/BlackEric001
Re: { }
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.10.23 16:22
Оценка: 6 (1)
Здравствуйте, BlackEric, Вы писали:

BE>Я сейчас глупость спрошу, но зачем в коде


BE>
BE>if (stage() is { } stages)
BE>

BE>{ }, что они означают?


BE>stage возвращает List<Stage>. Stages имеет этот же тип.



Это Property pattern. Внутри него можно указать свойства объекта и паттерны для них, например так:
if (stage() is { Count: > 0 } stages)


Если свойства не указаны, то трактуется также, как is not null

Конечно за такой код надо бить по рукам.
Re: { }
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.10.23 16:31
Оценка: 6 (1)
Здравствуйте, BlackEric, Вы писали:

BE>Я сейчас глупость спрошу, но зачем в коде


BE>
BE>if (stage() is { } stages)
BE>

BE>{ }, что они означают?
Это — property pattern с пустым списком пропертей.
Эквивалентно проверке на not null:

To check if the string s is non-null, you can write any of the following forms

if (s is object o) ... // o is of type object
if (s is string x) ... // x is of type string
if (s is {} x) ... // x is of type string
if (s is {}) ...

BE>stage возвращает List<Stage>. Stages имеет этот же тип.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 27.10.2023 1:34 Sinclair . Предыдущая версия .
Re[2]: Declaration
От: Qbit86 Кипр
Дата: 26.10.23 19:34
Оценка: 6 (1) +4
Здравствуйте, gandjustas, Вы писали:

G>Конечно за такой код надо бить по рукам.


Нет, за такой код бить по рукам не надо, это вполне легитимный способ, рекомендуемый анализаторами Roslyn или Rider.

G>Если свойства не указаны, то трактуется также, как is not null


Нет, is { } не эквивалентен is not null, потому что is not null не вводит имя переменной. Ты не можешь написать
if (stage() is not null stages)
    stages.SomeMethod();
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: { }
От: syrompe  
Дата: 26.10.23 21:20
Оценка: 5 (1) +2 -1 :)))
G>Если свойства не указаны, то трактуется также, как is not null

Ох уж это новый дивный мир си шарпа.
Я помнится похихикивал над несуразными примерами JavaScript'а, а теперь как-то неловко...

1. Сначала мы дружно писали
if(a!=null)

и спали спокойно
2. Потом нам завезли Nullable и местами пришлось писать
if(a.HasValue)

3. Потом завезли null propagation и стали появляться
if(a?.b?.HasValue==true)

4. Потом появились недоделанные паттерны
if(a is not null)

причем на некоторых проектах в codestyle прям жестко прописано что на null только через is проверять ибо оператор == злобный буратино переопределить может.
5. Теперь вот еще Property pattern'ы
if(a is {b: not null})

правда тут сюрприз бывает
Re: { }
От: Разраб  
Дата: 27.10.23 02:06
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Я сейчас глупость спрошу, но зачем в коде


BE>
BE>if (stage() is { } stages)
BE>

BE>{ }, что они означают?

Кто ж его знает. может ссылочный тип?
ЯП со сложным синтаксисом склонны к деградации, например F#
let xs = [1;2;3]
(* было *)
let x = xs.[0] // => 1
(* стало *)
let x = xs[0] // => 1
let x = xs [0] // =>  error FS3217: Это значение не является функцией, и применить его невозможно. Вы хотели обратиться к индексатору с помощью "xs[index]"?

иногда нужно остановится. например как сделали в схеме. просто сказали скобочек достаточно.
При это интересно следующее (это же тот же дотнет):
> let xs:List<Stage> = null;;
val xs : List<Stage> = null

> let r = match xs with | :? List<Stage> as x -> x.GetType().ToString() | _ -> "noname";;

  let r = match xs with | :? List<Stage> as x -> x.GetType().ToString() | _ -> "noname";;
  ------------------------^^^^^^^^^^^^^^

stdin(15,25): warning FS0067: Данная проверка типа или понижение будет всегда сохраняться

val r : string = "noname"

не пошел в первую ветку, хотя тип был жеско задан.

Может быть кондишины должны оставаться простыми? типа true/(false or nil).
А уже для специализации использовать полиморфизм?
Было же прекрасно в C# 1
https://rsdn.org/article/dotnet/asis.xml
Автор(ы): Владислав Чистяков (VladD2)
Дата: 18.12.2004
Работая над открытыми проектами, автор заметил, что операторы as и is многими программистами зачастую используются ненадлежащим образом. Результатом очередного двухчасового поиска ошибки и стала эта статья.


☭ ✊ В мире нет ничего, кроме движущейся материи.
Отредактировано 27.10.2023 2:18 Разраб . Предыдущая версия .
Re[3]: Declaration
От: Петрухин Эдуард Россия  
Дата: 27.10.23 06:12
Оценка: 11 (2) +1
Здравствуйте, Qbit86, Вы писали:

Q>Здравствуйте, gandjustas, Вы писали:


G>>Конечно за такой код надо бить по рукам.


Q>Нет, за такой код бить по рукам не надо, это вполне легитимный способ, рекомендуемый анализаторами Roslyn или Rider.


G>>Если свойства не указаны, то трактуется также, как is not null


Q>Нет, is { } не эквивалентен is not null, потому что is not null не вводит имя переменной. Ты не можешь написать

Q>
if (stage() is not null stages)
Q>    stages.SomeMethod();
Q>

Имя переменной можно отдельно ввести:
if (stage() is not null and var stages)
    stages.SomeMethod();

... но есть ньюанс с nullable value типами:
https://twitter.com/controlflow/status/1625933876018221069
https://sharplab.io/#v2:EYLgtghglgdgNAFxAJwK4wD4AEBMBGAWAChiA3CZAAgHtgArSgXkpgFMB3Sgb0oCFqAHk0oAKWAgD8ASkoAWHJQC+AbmLEoAM1G0GUAM7c+gkC2oIWqADaXKEGABNK5KgjxKZAZQAW1dgBUATwAHVhFXKVUiTW16Sn1DfgETSkNFFJS7R2dKBAVFTx9/YNDciLUiLFlKb19AkIAePwA+ET8cmUYmyiw8AE4w4uoNVqkIoA==
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[3]: { }
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 27.10.23 09:09
Оценка:
Здравствуйте, syrompe, Вы писали:

G>>Если свойства не указаны, то трактуется также, как is not null


S>Ох уж это новый дивный мир си шарпа.

S>Я помнится похихикивал над несуразными примерами JavaScript'а, а теперь как-то неловко...

Все, что ниже поскипано не относится к несуразностям. Просто стало больше возможностей, для более краткого и выразительного написания кода.
А с непривычки на Linq все плевались. Для них это было огромной несуразностью.
А вот в JS 1+"2" это несуразность
и солнце б утром не вставало, когда бы не было меня
Re[4]: { }
От: syrompe  
Дата: 27.10.23 10:04
Оценка:
S>Все, что ниже поскипано не относится к несуразностям. Просто стало больше возможностей, для более краткого и выразительного написания кода.
Ну скажем 6 способов проверить на нулл и каждый со своими ньюансами все же не есть хорошо.

S>А с непривычки на Linq все плевались. Для них это было огромной несуразностью.

Я вот до сих пор плююсь, но тут дело вкуса. С момента его появления у меня сменилось 3 проекта и нигде он не приветствовался (местами даже явным запретом в codestyle)

S>А вот в JS 1+"2" это несуразность

Тут да до JS еще очень далеко, но тенденция напрягает немного.
Re[5]: { }
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 27.10.23 11:12
Оценка:
Здравствуйте, syrompe, Вы писали:

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

S>Ну скажем 6 способов проверить на нулл и каждый со своими ньюансами все же не есть хорошо.

S>>А с непривычки на Linq все плевались. Для них это было огромной несуразностью.

S>Я вот до сих пор плююсь, но тут дело вкуса. С момента его появления у меня сменилось 3 проекта и нигде он не приветствовался (местами даже явным запретом в codestyle)

Я вот сейчас с ODATA работаю, и на Linq очень удобно REST запросы генерить Linq to ODATA
Я не говорю про DB и прочие коллекции
S>>А вот в JS 1+"2" это несуразность
S>Тут да до JS еще очень далеко, но тенденция напрягает немного.

Тенденция прежде всего из-за ПМ. К нему надо привыкнуть. Но значительно выразительнее.
и солнце б утром не вставало, когда бы не было меня
Re[5]: { }
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.10.23 11:14
Оценка: +1
Здравствуйте, syrompe, Вы писали:

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

S>Ну скажем 6 способов проверить на нулл и каждый со своими ньюансами все же не есть хорошо.
Почему? Если способы хорошие, то пусть работает. Если способы плохие, то компилятор может проверять это. И в случае C# — проверяет.
Re[3]: Declaration
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 27.10.23 11:30
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Нет, is { } не эквивалентен is not null, потому что is not null не вводит имя переменной. Ты не можешь написать

Q>
if (stage() is not null stages)
Q>    stages.SomeMethod();
Q>


про var уже ответили. Еще можно
https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/operators/patterns#parenthesized-pattern
if (input is not (float or double))
{
    return;
}
и солнце б утром не вставало, когда бы не было меня
Re[3]: { }
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.10.23 11:46
Оценка: 84 (2)
Здравствуйте, syrompe, Вы писали:

G>>Если свойства не указаны, то трактуется также, как is not null


S>Ох уж это новый дивный мир си шарпа.

S>Я помнится похихикивал над несуразными примерами JavaScript'а, а теперь как-то неловко...
Несуразица JS связана с его динамической типизацией. Много способов написать корректный код, который работает совсем не так как ожидаешь

В С# ситуация другая — там появляется много языковых фич, которые программисты не успевают изучать. Но все эти выражения помогают писать код гораздо более компактно, чем без них.

Например: проверка схемы данных в JSON (нерегулярной структуры). Два поля, если присутствуют в любом элементе, то должны быть согласованы, одно из них — строковый идентификатор объекта, второе — этого же объекта из трех частей (проект, модуль, имя) в виде пути на сайте
void ProcessContent(JsonNode node)
{
    switch (node)
    {
        case JsonObject obj:
            if (obj.TryGetPropertyValue("entity", out var entityNode) &&
                obj.TryGetPropertyValue("dataPath", out var dataPathNode) &&
                entityNode is JsonValue entityValue &&
                dataPathNode is JsonValue dataPathValue &&
                entityValue.TryGetValue<string>(out var entityId) &&
                dataPathValue.TryGetValue<string>(out var dataPath))
            {
                if (dataPath.Split("/") is
                    ["api", "v1.0", "dynamicEntityTable", var projectName, var moduleName, var name])
                {
                    // ....
                }
                else
                {
                    // ....
                }
            }
            foreach (var pair in obj)
            {
                await ProcessContent(pair.Value);
            }

            break;
        case JsonArray arr:
            foreach (var subNode in arr)
            {
                await ProcessContent(subNode);
            }

            break;
    }
}


Написать то же самое без PM и out var займет в разы дольше.
Re[3]: { }
От: Sinclair Россия https://github.com/evilguest/
Дата: 27.10.23 14:03
Оценка: 20 (2) +1
Здравствуйте, syrompe, Вы писали:

G>>Если свойства не указаны, то трактуется также, как is not null


S>Ох уж это новый дивный мир си шарпа.

S>Я помнится похихикивал над несуразными примерами JavaScript'а, а теперь как-то неловко...
Отличная шутка, коллега! Я тоже посмеялся.

S>1. Сначала мы дружно писали

S>
S>if(a!=null)
S>

S> и спали спокойно
S>2. Потом нам завезли Nullable и местами пришлось писать
S>
S>if(a.HasValue)
S>

Хм. А в каком это контексте пришлось?
Чем вас не устроило продолжать писать if(a!=null)?

S>3. Потом завезли null propagation и стали появляться

S>
S>if(a?.b?.HasValue==true)
S>

Опять же — если вас категорически не устраивает возможность писать if(a?.b != null), то вы можете продолжать пользоваться старым добрым if(a != null && a.b != null).
Возможность писать if (((а == null) == false).ToString() == "true") была доступна сразу в C# 1.0, тут за десять мажорных релизов не изменилось ровным счётом ничего.

S>4. Потом появились недоделанные паттерны

S>
S>if(a is not null)
S>

Это просто такой corner case на пересечении нескольких фич, каждая из которых была спроектирована для своей цели.
Но язык должен позволять комбинировать фичи не только конкретным способом, но и любым легальным.
Вы же заметили, что теперь можно писать не только if (a == 42), но и if(a is 42)?
Над этим можно было бы похихикать, если бы не один нюанс: набор разрешённых компайл-тайм типов a в этих случаях отличается.
В частности:
bool CheckFor42(object a)
{
  return a == 42; // fail
  return a is 42;  // fine
}

Так что второй вариант безо всякого юмора гораздо удобнее, чем дедовский
  return a is int && (a as int) == 42;

Ну, а возможность таким же образом сравнивать с null — побочный эффект, не запрещать же такую запись только от того, что константа null совместима с любым reference или nullable типом.

S>причем на некоторых проектах в codestyle прям жестко прописано что на null только через is проверять ибо оператор == злобный буратино переопределить может.

Ну так и замечательно, в чём проблема?
В том, что вам нестерпимо хотелось писать if (!object.ReferenceEquals(a, null)), а вам злые дяди запрещают?
Ведь если оператор сравнения перегружен каким-то нехорошим образом так, что он неверно проверяет на null, то у проекта проблемы тут не в code style. И при помощи is эти проблемы не решить.

S>5. Теперь вот еще Property pattern'ы

S>
S>if(a is {b: not null}) 
S>

S>правда тут сюрприз бывает
Даже интересно стало, какой сюрприз. Ну, и, собственно, что заставляет вас писать именно так, если вам по-прежнему хочется if(a != null && a.b != null).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: { }
От: _FRED_ Черногория
Дата: 27.10.23 15:16
Оценка:
Здравствуйте, gandjustas, Вы писали:

G> entityValue.TryGetValue<string>(out var entityId) &&
G> dataPathValue.TryGetValue<string>(out var dataPath))

Прошу прощенгия, а почему не так:
entityValue.TryGetValue(out string entityId) &&
dataPathValue.TryGetValue(out string dataPath))

?
Help will always be given at Hogwarts to those who ask for it.
Re: { }
От: _FRED_ Черногория
Дата: 27.10.23 15:30
Оценка: +2
Здравствуйте, BlackEric, Вы писали:

BE>Я сейчас глупость спрошу, но зачем в коде

BE>if (stage() is { } stages)

BE>{ }, что они означают?
BE>stage возвращает List<Stage>. Stages имеет этот же тип.

Я извиняюсь, что с непрошенными советами лезу, не стесняйтель заминусить.

Но кажется не очень удобной идея возврата null вместо List<Stage> (Guidelines for Collections / Collection Properties and Return Values):

❌ DO NOT return null values from collection properties or from methods returning collections. Return an empty collection or an empty array instead.

The general rule is that null and empty (0 item) collections or arrays should be treated the same.

Потому как раз, что пользователю такого свойства или метода неудобно делать проверки на нулл, проще проверить, пуста ли коллекция.

Если вы возвращаете null чтобы не создавать лишний раз пустой список (когда он не нужен), то тут лучше изменить тип возвращаемого значения на, например, массив или ридонли интерфейс (от IEnumerable<> до IReadOnlyList<>) и возвращать Array.Empty<Stage>(); вметсо нулла. а пользователь уже, если и когда ему будет нужно, сможет скопировать полученную коллекцию в List<Stage>. Если такое лишнее копирование не устраивает, то нужна будет своя реализация, например, IReadOnlyList<> с методом ToList() которая для пустой "внутренней" коллекции создаст новый List<>, а для уже готового List<> его и вернёт.
Help will always be given at Hogwarts to those who ask for it.
Re[4]: `is` vs. `==`
От: Qbit86 Кипр
Дата: 27.10.23 15:31
Оценка: 80 (1) +1
Здравствуйте, Sinclair, Вы писали:

S>Вы же заметили, что теперь можно писать не только if (a == 42), но и if(a is 42)?

S>Над этим можно было бы похихикать, если бы не один нюанс: набор разрешённых компайл-тайм типов a в этих случаях отличается.

Разница ещё и в том, что паттерн, с которым значение сравнивается через is, должен быть коснтантой; часто это enum. То есть is более точная и строгая форма записи, чем ==. Я предпочитаю is, когда сравниваю с константой.

S>Ведь если оператор сравнения перегружен каким-то нехорошим образом так, что он неверно проверяет на null, то у проекта проблемы тут не в code style.


А вот сейчас было больно; я работаю с Unity :(
Глаза у меня добрые, но рубашка — смирительная!
Re[5]: { }
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.10.23 15:32
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, gandjustas, Вы писали:


_FR>Прошу прощенгия, а почему не так:

_FR>
_FR>entityValue.TryGetValue(out string entityId) &&
_FR>dataPathValue.TryGetValue(out string dataPath))
_FR>

_FR>?

Не знаю, видимо из примера скопипастили изначально.
Re[2]: Populate()
От: Qbit86 Кипр
Дата: 27.10.23 15:37
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Если такое лишнее копирование не устраивает, то нужна будет своя реализация, например, IReadOnlyList<> с методом ToList() которая для пустой "внутренней" коллекции создаст новый List<>, а для уже готового List<> его и вернёт.


Или вместо возврата колекции предоставить метод Populate<TCollection>(TCollection collection) where TCollection..., который заполняет уже существующую коллекцию (которую аллоцирует и предоставляет вызывающая сторона).
Глаза у меня добрые, но рубашка — смирительная!
Re[3]: Populate()
От: _FRED_ Черногория
Дата: 27.10.23 17:04
Оценка:
Здравствуйте, Qbit86, Вы писали:

_FR>>Если такое лишнее копирование не устраивает, то нужна будет своя реализация, например, IReadOnlyList<> с методом ToList() которая для пустой "внутренней" коллекции создаст новый List<>, а для уже готового List<> его и вернёт.


Q>Или вместо возврата колекции предоставить метод Populate<TCollection>(TCollection collection) where TCollection..., который заполняет уже существующую коллекцию (которую аллоцирует и предоставляет вызывающая сторона).


Так цимес вроде именно в том, что вызывающей стороне не известно количество элементов и лишних аллокаций на пустые коллекции хочется как раз избежать.

P.S. С [tt] классно
Help will always be given at Hogwarts to those who ask for it.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.