Здравствуйте, gandjustas, Вы писали:
G>В С# ситуация другая — там появляется много языковых фич, которые программисты не успевают изучать. Но все эти выражения помогают писать код гораздо более компактно, чем без них.
G>Например: проверка схемы данных в JSON (нерегулярной структуры). Два поля, если присутствуют в любом элементе, то должны быть согласованы, одно из них — строковый идентификатор объекта, второе — этого же объекта из трех частей (проект, модуль, имя) в виде пути на сайте G>
G> if (obj.TryGetPropertyValue("entity", out var entityNode) &&
G> obj.TryGetPropertyValue("dataPath", out var dataPathNode) &&
G> entityNode is JsonValue entityValue &&
G> dataPathNode is JsonValue dataPathValue &&
G> entityValue.TryGetValue<string>(out var entityId) &&
G> dataPathValue.TryGetValue<string>(out var dataPath))
G> {
G> }
G>
G>Написать то же самое без PM и out var займет в разы дольше.
Только вот когда в разы дольше, тогда можно дописать нормальную диагностику ошибки с сообщением, на каком элементе упал парсинг. А в приведённом примере единственное что можно написать, это
else
{
throw new Exception("Что-то пошло не так");
}
Здравствуйте, _FRED_, Вы писали:
_FR>Так цимес вроде именно в том, что вызывающей стороне не известно количество элементов и лишних аллокаций на пустые коллекции хочется как раз избежать.
Так чтобы это количество стало известно, в современных API в BCL добавляют методы вроде GetByteCount() или GetMaxEncodedToUtf8Length(). Обычно в сценариях работы со span'ами, но и в обычных можно. Общая идея: не брать на себя аллокацию, пусть вызывающая сторона выделяет или берёт из пула.
_FR>P.S. С [tt] классно
_FR>❌ DO NOT return null values from collection properties or from methods returning collections. Return an empty collection or an empty array instead.
_FR>The general rule is that null and empty (0 item) collections or arrays should be treated the same.
_FR>Потому как раз, что пользователю такого свойства или метода неудобно делать проверки на нулл, проще проверить, пуста ли коллекция.
_FR>Если вы возвращаете null чтобы не создавать лишний раз пустой список (когда он не нужен), то тут лучше изменить тип возвращаемого значения на, например, массив или ридонли интерфейс (от IEnumerable<> до IReadOnlyList<>) и возвращать Array.Empty<Stage>(); вметсо нулла. а пользователь уже, если и когда ему будет нужно, сможет скопировать полученную коллекцию в List<Stage>. Если такое лишнее копирование не устраивает, то нужна будет своя реализация, например, IReadOnlyList<> с методом ToList() которая для пустой "внутренней" коллекции создаст новый List<>, а для уже готового List<> его и вернёт.
У нас так часто в проекте. Возвращается null или пустой список или заполненный. Null как правило, если документ только создается.
Здравствуйте, vmpire, Вы писали:
V>Только вот когда в разы дольше, тогда можно дописать нормальную диагностику ошибки с сообщением, на каком элементе упал парсинг.
Во-первых это Exception-free код, там никаких путей исполнения через эксепшены нет. Если что-то падает, то никто не перехватывает.
Во-вторых текущий проверяемый JsonObject доступен в том числе для репортинга.
V>А в приведённом примере единственное что можно написать, это V>
V> else
V> {
V> throw new Exception("Что-то пошло не так");
V> }
V>
Ты удивишься, но в реальном коде как раз возвращается в каком элементе возникает ошибка.
V>Так что это палка о двух концах.
Конечно нет, просто кривизна рук разная.
Здравствуйте, _FRED_, Вы писали:
_FR>❌ DO NOT return null values from collection properties or from methods returning collections. Return an empty collection or an empty array instead.
Логика требует, очевидно. 0 — ничего нет или не получилось?
null — как индикатор что что-то пошло нет так, или кидать исключение,
в любом случае придется как-то обработать 3-й вариант.
иначе получаем скрытую ошибку в программе.
Здравствуйте, Sinclair, Вы писали:
S>Ведь если оператор сравнения перегружен каким-то нехорошим образом так, что он неверно проверяет на null, то у проекта проблемы тут не в code style. И при помощи is эти проблемы не решить. S>Что не так с operator== в Unity?
У игровых объектов (или компонентов на них висящих) может быть статус «разрушен» — когда они удалены из дерева сцены, их ресусрсы освобождены, они не могут получать событий обновления, etc.
Так вот, вместо того, чтобы добавить в API свойство или метод IsAlive или IsDisposed, расработчики Unity переопределили operator ==, изменив его логику для случая сравнения с null. Проверка вида if (myGameObject == null) возвращает true не только когда ссылка is null, но и если объект разрушен; причём другого способа проверить разрушенность нет.
А если ты вызываешь методы движка на разрушенном объекте (имея на него ненулевую ссылку), то разработчики выбрасывают исключение типа NullReferenceException.
Здравствуйте, Qbit86, Вы писали:
Q>У игровых объектов (или компонентов на них висящих) может быть статус «разрушен» — когда они удалены из дерева сцены, их ресусрсы освобождены, они не могут получать событий обновления, etc. Q>Так вот, вместо того, чтобы добавить в API свойство или метод IsAlive или IsDisposed, расработчики Unity переопределили operator ==, изменив его логику для случая сравнения с null. Проверка вида if (myGameObject == null) возвращает true не только когда ссылка is null, но и если объект разрушен; причём другого способа проверить разрушенность нет. Q>А если ты вызываешь методы движка на разрушенном объекте (имея на него ненулевую ссылку), то разработчики выбрасывают исключение типа NullReferenceException.
Q>Абсолютно проклято.
На первый взгляд да. А в каких сценариях требуется отличать null-ссылку от ссылки на разрушенный объект, который уже удалён из дерева сцены?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>На первый взгляд да. А в каких сценариях требуется отличать null-ссылку от ссылки на разрушенный объект, который уже удалён из дерева сцены?
Например, null-ссылка может быть признаком того, что её не проинициализировали — не привязали в Редакторе перетаскиванием одного игрового объекта в поле на другом объекте. Такую ситуацию надо обрабатывать иначе, чем просто ссылку на разрушенный объект. Anyway, атомарным кирпичиком должен быть IsDisposed(), из которого можно при необходимости собрать статический метод (расширения) IsNullReferenceOrDisposed(). А не наоборот, когда у тебя цепочка if (go is null) { … } else if (go == null) { … }, причём внутри второй проверке ещё раз повторно происходит и первая (ссылочное сравнение на null).
Сопряжённым источником фрустрации для многих разработчиков Unity (они в основном не специалисты в языке) было появление в очередной версии Unity поддержки null propagation и null coalescing в синтаксисе C#. Раньше они не задумывались, какой механизм лежит за тем, что их ссылки как бы «обнуляются» при смерти объекта. Многим казалось, что это такая магия рантайма (а не языка — переопределение оператора). И когда они стали заменять проверки if (go != null) go.Foo() на новый модный null propagation go?.Foo(), получали изменение семантики и неожиданный NullReferenceException (вместо хотя бы ObjectDisposedException).