All streams
Search
Write a publication
Pull to refresh
4
0
Send message
Будет еще одна часть? Вряд ли это все библиотеки. Например есть еще clize.
Есть еще SpanJson. Тот еще велосипед, судя по оформлению истории комитов, но зато поддерживает аттрибуты-конвертеры.

Набросал бенч на коленке сериализацию и десериализацию и получилось:

core 2.2.2

Newtonsoft: 1 (allocated 35.48 MB)
Velo: 0.43 (allocation 12.36 MB)
SpanJson: 0.18 (allocation 2.75 MB)

Newtonsoft: 1 (allocated 25.45 MB)
Velo: 0.36 (allocation 5.93 MB)
SpanJson: 0.27 (allocation 4.4 MB)
Разве?.. По логике вещей идет обычное планирование продолжения в ThreadPool и сначала будут сделаны запланированные ранее задачи, чем дело дойдет до этого продолжения. Иначе не будет разницы между обычными потоками без await. Нет никакой гарантии выполнения в том же потоке при ConfigureAwait(false), да и ConfigureAwait(true) тоже, если нет контекста, который жестко прибьет гвоздями продолжение к какому-то потоку.

Может тяготеть исполнять в том же потоке — да, но это не гарантируется.
А с чего он взялся решать такие вопросы
Именно так. Конечно можно сказать, что не дело сериализатора проверять заполненность и пусть проверяет уже на месте. Но если апи четко объявляет, что такого не будет (спека), то нарушение постусловия означает, что система работает неправильно.
Допустимо ли это и пропустить дальше или упасть «fail fast» зависит от приложения. Все эти «fail fast» обычно все исчезают в процессе разработки и тестирования. И если далее такое будет, то это ну совсем нештатная ситуация, которая требует немедленного внимания, потому что логике быть не должна ни в коем случае.

И да, поле с возможностью null будет nullable (или помечено аттрибутом, раз уж #nullable не зашел)

Постусловия можно поменять
Нельзя. Если имеется код, который завязан на контракт (спеку) кода сериализации, то ничего менять уже нельзя.

зы: конечно вы правы про то, что «каждый должен заниматься своим делом». Но подход fail-fast себя оправдывает, если ошибки, которые он ловит, можно починить до релиза. Если же это сервис, который должен быть устойчивый ко всем «а что если», то там предусматриваются все варианты, а не «зови программиста»
Ну это мы в сторону ушли (моя вина). Не должен транспортный давать гарантии модели. Он должен давать гарантии получения данных «не потерялось и дошло как надо». Но мы ушли в обсуждение архитектуры, а ведь проблема куда проще.

Речь идет о сериализаторе. К нему есть требование дать гарантию, что он заполнит все поля в классе, тип которого ему передадут для материализации (и они не будут дефолтными). Это у него постусловия такие. И сериализатор достаточно глуп, чтобы отследить это прямо в процессе разбора данных. Приходится проверять постусловием
Эти постусловия четко отражены в спеке и следуя «концепции баррикады» можно не писать дополнительные проверки на это в клиентском коде и не получить NRE.

и с #nullable в их текущей реализации выбор очевиден
1 инициализировать дефолтные и поломать постусловия, от чего пострадает клиентский код (breaking change) — и все это с нулевой выгодой
2 заставить в клиентском коде проставить везде "!" и заставлять в новом коде это писать — и снова выгоды не вижу
3 оставить все как есть.

Все зависит от точки зрения. Ваша цепочка выглядит примерно так:

--> json --> десериализация в PersonDTO --> Person(PersonDTO dto) -->

«десериализация в PersonDTO» может быть библиотекой-клиентом к некому апи, которую клиентский код может использовать. Она, можно сказать, транспортный слой, который при этом ничего не знает про business logic. И нормально, что этот слой валидирует полное получение данных, хоть и не может валидировать их суть. Я получаю ошибку сразу «fail fast», и к тому же на уровне, где она произошла.

Если я получаю из api погоду в виде иммутабельного объекта Weather c 3мя свойствами «город, температура, влажность», то рассматривать Weather как dto и создать WeatherModel, или просто использовать как есть? — каждый решает сам, но в случае «использовать как есть» у нас все равно есть гарантия транспортного слоя, что «город не null» и «температура настоящая, а не дефолтная»

И если переделка под nullable привносит только необходимость прописывать восклицательные знаки (или же отказ от проверок транспортного слоя), то я лучше откажусь от nullable
Возможно и не успел. Поэтому и спросил. На гитхабе сложно следить где что там решили, да и часто это просто болтовня, а не «решили».

Пример реальной попытки: сериализатор требует пустого конструктора и заполняет только те свойства, что может заполнить (причем через internal сеттеры). Если не заполнены, то это нештатная ситуация и простой валидатор проверяет на null зная, что ни одно поле не может быть null. Сложный валидатор невозможен — ему тут не место. И все работает, все хорошо, только фатальный недостаток — не использует новых фич

Пробую #nullable. Инициализация дефолтными значениями не прошла. Сразу поломался валидатор на незаполненность, а больше ничего и не проверить. Попытка обвесить модельки #nullable disable тоже ничего не дало. В итоге сделал свойства моделек nullable и начал массово (реально в сотнях мест) проставлять! но на полпути задался вопросом «а зачем?»

Код остался прежним, но я получил требование в клинтском коде писать! (и необходимость помнить, что! обязателен, ведь non-null гарантирован логикой, nullable из-за компилятора), а вот выгоду я увидеть не смог

и придумать как переделать, да чтобы не городить жуткие костыли из-за слабости поддержки nullable в языке, я тоже не смог, поэтому вернул все обратно.
Если по дефолту сделать nullable
Ну так оно и так во всем существующем коде по дефолту nullable. И все эти годы так было. И именно это «по дефолту null и инициализации не было и никто не подсказал про забытую инцицализацию» и является основной причиной ошибок NRE.

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

А так лучше бы они records сделали — крайне полезная вещь.
Вы не понимаете. Хватает ситуаций «я уверен, что на момент чтения оно не будет null, поэтому не заставляй меня делать его nullable, раз уж у компилятора не хватает ума самому это вычислить». В котлин для этого есть модификатор lateinit (по названию видно что он делает). Это и различные dto без конструкторов, методы вида Init, на границе с UI тоже пригождается и на границе с жавой (там ведь тоже никакого null safety). Вот прям такая же ситуация и с шарпом — множество обычного кода, который знать не знает про nullable

Инициализация в конструкторе это костыль
1. Я уже говорил, что эта инициализация просто нагружает GC лишний раз. Можно сказать что это короткоживущие объекты, но есть пункт 2
2. Может быть совсем не просто инициализировать свойство, которое суть сложный объект, да еще с приватным/интернал конструктором (сериализатору это без разницы, а вот вы будете в тупике)
3. И даже если можно, то в случае проблем с десериализацией вы можете получить неконсистентное состояние (новые данные + бесполезное дефолтные)

А теперь про гарантии. Вдруг десериализатор не заполнит некоторые свойства. Сравните:
а) В случае lateinit я просто сделаю проверку на null всех свойств 1 раз (и все) после десериализации. Я выполню гарантии в рантайме и у меня есть способ сказать компилятору «я сам».
б) в случае «дефолтные в конструкторе» я не смогу отличить что новое, а что старое. Мне придется делать полный валидатор, что уже перебор. Также он может быть невозможен, если значение свойства не отличить — и тогда придется все делать nullable. А это приведет к тому, что в 1000 мест мне придется проставлять!

Ожидалось, что шарп не будет изобретать свое, а возьмет удачные решения с других языков, но он взял только базовое и это явно недостаточно.
А в чем отличие? Ну кроме места где будет инициализация? Результат тот же.
Nullable Reference Types — то, что должно быть изначально. В котлине он изначально и там с этим очень неплохо. А вот в c#… прямо сейчас я чиню очередной NRE, причем в библиотеке, а ведь его могло бы и не быть, будь от этого защита.

и «поддержка в runtime» не нужна. Ведь основная задача этой функциональности — позволить на этапе написания кода избегать NRE с нулевой стоимостью во время выполнения.

Просто «поздно решили внедрить» и поэтому приходится делать это костыльно
Другое. Запрос к api возвращает json, который десериализуем в граф объектов. И хоть мы знаем, что у нас после этого будут инициализированы все свойства, приходится определять все поля nullable и потом в тысяче мест добавлять!.. Или же инициализировать свойства значениями, что в случае вложенных классов может быть очень развесисто и попросту захламляют кучу, ведь сразу после создания объекта все эти свойства будут перезаписаны.

А хотелось бы сказать компилятору «да я уверен, что там null не будет, не заставляй меня их инициализировать»
А будет ли в c# аналог lateinit того же Котлина?
И снова не вижу разницы.

Folder «C:\Windows\WinSxS»

Folders: 23887
Files: 81983
Files size: 6,33 GB
Allocated size: 6,31 GB (99%)

опция «сканировать символические ссылки» не влияет на результат.
Банально, выделите все файлы на диске С

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

Готовых утилит нет, ибо никому не нужно.

Ну почему же. Нужно и есть. Вот та же du

Но я неправильно смотрел. Ключ -u не исключает хардлинки, а, наоборот, включает хардлинки в сумму (вот что значит прочесть so вместо справки)

без него у WinSxS нет особой разницы, а windows 21 гб.
И где и как это смотреть?
проводник c:/Windows/WinSxS:
размер: 6 793 220 351
на диске: 6 951 350 272

> du -u c:/Windows/WinSxS (du от sysinternals)
Files: 81979
Directories: 23888
Size: 6 793 154 099 bytes
Size on disk: 7 123 623 936 bytes
ладно. может хардлинки не внутри WinSxS, а вообще вся папка винды
проверяем

проводник c:/Windows/:
размер: 27 590 010 367
на диске: 26 928 803 840

> du -u c:/Windows/
Files: 151579
Directories: 32268
Size: 27 351 525 630 bytes
Size on disk: 26 939 879 424 bytes

неправильно смотрю? чем еще посмотреть?
Как раз при проблемах с Windows Update и предлагают чистить этот кэш.

Потому что при проблемах с инсталлом/апдейтом чего угодно это самый частый рецепт. А в случае с виндой, так вообще первый с ее невразумительными ошибками и бесполезной службой «обнаружение проблем».
Только вот чистка этого кеша при нормальной работе службы как раз и может привести к тем проблемам обновления. У меня приводила, хоть и чистил правильно останавливая службы. И хоть я использую уже wumt, но трогать эту папку = риск

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

Ну это как сказать. Недавно вычистил package cache (не nuget) от VS2017 — так даже родной инсталлер не помог. Это хорошо, что есть в поставке студии «InstallCleanup.exe -full», но полная переустановка всей студии и всех расширений мало приятное занятие.

Но все же размер этой папки просто ужасен. Решил рискнуть и нагуглил PatchCleaner, который вычистил из Installer 7.6 гига хлама по его мнению.
Очистка SoftwareDistribution с большой вероятностью сломает windows update. Сколько его раньше чистил — столько и ломалось.
А чистка Installer приведет к проблемам с установленным софтом.
Очистку этих папок можно себе позволить только если больше не хочется обновлять windows или менять установленный софт
C:\Windows — 35 GB
из них
C:\Installer — 12 GB
C:\SoftwareDistribution — 3 GB
То есть 15 гигов лежат файлы, которые всегда можно скачать. И их тронуть нельзя.
C:\WinSxS — 6.3 GB
Бесполезный неудаляемый жир, который винда накопила и похудеть ее не заставишь.
C zaborona проще. Для тех, кто не дружит с консолью, есть пакет luci-app-wireguard, а также есть скрипты настройки сервера. Да и правила меняются редко, что убирает необходимость автоматического обновления.

Information

Rating
Does not participate
Registered
Activity