Здравствуйте, gandjustas, Вы писали:
G>Конечно за такой код надо бить по рукам.
Нет, за такой код бить по рукам не надо, это вполне легитимный способ, рекомендуемый анализаторами Roslyn или Rider.
G>Если свойства не указаны, то трактуется также, как is not null
Нет, is { } не эквивалентен is not null, потому что is not null не вводит имя переменной. Ты не можешь написать
if (stage() is not null stages)
stages.SomeMethod();
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'ы
Здравствуйте, 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
Здравствуйте, 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();
Здравствуйте, syrompe, Вы писали:
G>>Если свойства не указаны, то трактуется также, как is not null
S>Ох уж это новый дивный мир си шарпа. S>Я помнится похихикивал над несуразными примерами JavaScript'а, а теперь как-то неловко...
Все, что ниже поскипано не относится к несуразностям. Просто стало больше возможностей, для более краткого и выразительного написания кода.
А с непривычки на Linq все плевались. Для них это было огромной несуразностью.
А вот в JS 1+"2" это несуразность
и солнце б утром не вставало, когда бы не было меня
S>Все, что ниже поскипано не относится к несуразностям. Просто стало больше возможностей, для более краткого и выразительного написания кода.
Ну скажем 6 способов проверить на нулл и каждый со своими ньюансами все же не есть хорошо.
S>А с непривычки на Linq все плевались. Для них это было огромной несуразностью.
Я вот до сих пор плююсь, но тут дело вкуса. С момента его появления у меня сменилось 3 проекта и нигде он не приветствовался (местами даже явным запретом в codestyle)
S>А вот в JS 1+"2" это несуразность
Тут да до JS еще очень далеко, но тенденция напрягает немного.
Здравствуйте, syrompe, Вы писали:
S>>Все, что ниже поскипано не относится к несуразностям. Просто стало больше возможностей, для более краткого и выразительного написания кода. S>Ну скажем 6 способов проверить на нулл и каждый со своими ньюансами все же не есть хорошо.
S>>А с непривычки на Linq все плевались. Для них это было огромной несуразностью. S>Я вот до сих пор плююсь, но тут дело вкуса. С момента его появления у меня сменилось 3 проекта и нигде он не приветствовался (местами даже явным запретом в codestyle)
Я вот сейчас с ODATA работаю, и на Linq очень удобно REST запросы генерить Linq to ODATA
Я не говорю про DB и прочие коллекции S>>А вот в JS 1+"2" это несуразность S>Тут да до JS еще очень далеко, но тенденция напрягает немного.
Тенденция прежде всего из-за ПМ. К нему надо привыкнуть. Но значительно выразительнее.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, syrompe, Вы писали:
S>>Все, что ниже поскипано не относится к несуразностям. Просто стало больше возможностей, для более краткого и выразительного написания кода. S>Ну скажем 6 способов проверить на нулл и каждый со своими ньюансами все же не есть хорошо.
Почему? Если способы хорошие, то пусть работает. Если способы плохие, то компилятор может проверять это. И в случае C# — проверяет.
Здравствуйте, 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 займет в разы дольше.
Здравствуйте, 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; // failreturn 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).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
❌ 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.
Здравствуйте, Sinclair, Вы писали:
S>Вы же заметили, что теперь можно писать не только if (a == 42), но и if(a is 42)? S>Над этим можно было бы похихикать, если бы не один нюанс: набор разрешённых компайл-тайм типов a в этих случаях отличается.
Разница ещё и в том, что паттерн, с которым значение сравнивается через is, должен быть коснтантой; часто это enum. То есть is более точная и строгая форма записи, чем ==. Я предпочитаю is, когда сравниваю с константой.
S>Ведь если оператор сравнения перегружен каким-то нехорошим образом так, что он неверно проверяет на null, то у проекта проблемы тут не в code style.
Здравствуйте, _FRED_, Вы писали:
_FR>Если такое лишнее копирование не устраивает, то нужна будет своя реализация, например, IReadOnlyList<> с методом ToList() которая для пустой "внутренней" коллекции создаст новый List<>, а для уже готового List<> его и вернёт.
Или вместо возврата колекции предоставить метод Populate<TCollection>(TCollection collection) where TCollection..., который заполняет уже существующую коллекцию (которую аллоцирует и предоставляет вызывающая сторона).
Здравствуйте, 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.