День 1284. #ЗаметкиНаПолях
Генерация Сортируемых Guid с Помощью NewId. Начало
NewId предназначен случаев, когда вам нужен уникальный идентификатор, но, по возможности, сортируемый и предсказуемый, например для первичных ключей в базах данных.
Большинство используют:
-
-
Рассмотрим плюсы и минусы каждого подхода.
1. Генерация в базе данных
Плюсы:
- Первичные ключи получают красивые, монотонно возрастающие (и обычно последовательные) идентификаторы.
- Упрощается работа с тестовыми данными. Идентификаторы часто появляются в URL-адресах, и простые последовательные идентификаторы очень удобно использовать.
Минусы:
- Невозможность использования некоторых паттернов проектирования. Например, распространённый подход к идемпотентности заключается в создании идентификатора на клиенте и отправке его в запросе. Это устраняет дублирование и гарантирует, что вы не вставите один и тот же объект дважды, так как легко обнаружить повторяющиеся запросы на вставку. Такой подход обычно невозможен с идентификаторами, сгенерированными базой данных.
- Усложнение кода вставки, чтобы возвращать сгенерированные идентификаторы. ORM, такие как EF Core, инкапсулируют эту логику, но, например, при использовании Dapper, вам придётся это делать самому.
- При вставке тысяч строк в секунду, «блокировка» базы данных вокруг генератора идентификаторов иногда может стать узким местом.
- Масштабирование «вширину» затруднено из-за необходимости координировать идентификаторы между всеми серверами.
2. Генерация GUID на клиенте
Плюсы:
- Лёгкость. Все современные языки имеют доступные генераторы UUID; в .NET это
- Лёгкий доступ к различным шаблонам идемпотентности. Если запрос на вставку завершается сбоем из-за ошибки сервера, можно безбоязненно отправить тот же запрос ещё раз, зная, что сервер сможет идентифицировать возможный дубликат (т.к. ключ тот же), и избежать создания повторяющихся сущностей.
Случайность Guid - это и их сила, и их слабость.
Минусы:
- Для разработчика, тестирующего код, с
- В базе данных эта случайность идентификаторов может привести к серьезной фрагментации индекса, что увеличивает размер вашей базы данных и влияет на общую производительность. Также UUID являются 128-битными по сравнению с 32-битными целыми числами, поэтому больше и чистый размер хранимых данных.
Окончание следует…
Источник: https://andrewlock.net/generating-sortable-guids-using-newid/
Генерация Сортируемых Guid с Помощью NewId. Начало
NewId предназначен случаев, когда вам нужен уникальный идентификатор, но, по возможности, сортируемый и предсказуемый, например для первичных ключей в базах данных.
Большинство используют:
-
int
и позволяют базе данных генерировать первичный ключ при вставке строки,-
Guid
, генерируя идентификатор в своём приложении и вставляя его в строку.Рассмотрим плюсы и минусы каждого подхода.
1. Генерация в базе данных
Плюсы:
- Первичные ключи получают красивые, монотонно возрастающие (и обычно последовательные) идентификаторы.
- Упрощается работа с тестовыми данными. Идентификаторы часто появляются в URL-адресах, и простые последовательные идентификаторы очень удобно использовать.
Минусы:
- Невозможность использования некоторых паттернов проектирования. Например, распространённый подход к идемпотентности заключается в создании идентификатора на клиенте и отправке его в запросе. Это устраняет дублирование и гарантирует, что вы не вставите один и тот же объект дважды, так как легко обнаружить повторяющиеся запросы на вставку. Такой подход обычно невозможен с идентификаторами, сгенерированными базой данных.
- Усложнение кода вставки, чтобы возвращать сгенерированные идентификаторы. ORM, такие как EF Core, инкапсулируют эту логику, но, например, при использовании Dapper, вам придётся это делать самому.
- При вставке тысяч строк в секунду, «блокировка» базы данных вокруг генератора идентификаторов иногда может стать узким местом.
- Масштабирование «вширину» затруднено из-за необходимости координировать идентификаторы между всеми серверами.
2. Генерация GUID на клиенте
Плюсы:
- Лёгкость. Все современные языки имеют доступные генераторы UUID; в .NET это
Guid.NewGuid()
, который возвращает случайный 128-битный идентификатор. Генерация его на клиенте и вставка позволяет не беспокоиться о том, что было сгенерировано в БД. В EF Core или Dapper, Postgres или SqlServer - всё одинаково. Данные перемещаются только в одном направлении: от клиента к базе данных.- Лёгкий доступ к различным шаблонам идемпотентности. Если запрос на вставку завершается сбоем из-за ошибки сервера, можно безбоязненно отправить тот же запрос ещё раз, зная, что сервер сможет идентифицировать возможный дубликат (т.к. ключ тот же), и избежать создания повторяющихся сущностей.
Случайность Guid - это и их сила, и их слабость.
Минусы:
- Для разработчика, тестирующего код, с
/my-entity/be170000-f22d-18db-02db-08da21702e9f
определённо не так просто работать, как с /my-entity/1
.- В базе данных эта случайность идентификаторов может привести к серьезной фрагментации индекса, что увеличивает размер вашей базы данных и влияет на общую производительность. Также UUID являются 128-битными по сравнению с 32-битными целыми числами, поэтому больше и чистый размер хранимых данных.
Окончание следует…
Источник: https://andrewlock.net/generating-sortable-guids-using-newid/
👍3
День 1285. #NuGet
Генерация Сортируемых Guid с Помощью NewId. Окончание
Начало
NewId вместо полностью случайных Guid предоставляет UUID, который можно легко отсортировать. Рассмотрим простое приложение:
-
-
-
NewId использует 3 разных источника для создания идентификатора:
1. ID машины/процесса – константа для данной машины (может быть настроена для включения идентификатора процесса).
2. Временную метку - обеспечивает базовый порядок идентификатора.
3. Последовательность - увеличивающийся идентификатор.
Объединив все 3 вместе, вы можете получить идентификатор, который (с натяжкой) упорядочен благодаря компоненту метки времени. Включив идентификатор рабочего процесса, вы можете заставить процессы генерировать независимые ID, избегая при этом коллизий. Это можно сделать, например, вызвав в начале программы:
Очевидно, что такие ID приводят к гораздо менее фрагментированному индексу базы данных. Конечно, с идеально последовательными целыми числами они не сравнятся. Но сравнение индексов в оригинальной статье показало, что полностью случайные Guid приводят к почти 99% фрагментации индекса, тогда как фрагментация индекса NewId составляет лишь 5%.
Сгенерированные идентификаторы предсказуемы по своей сути. Их не следует использовать в сценариях, где желательна непредсказуемость. Эти идентификаторы НЕ должны использоваться для:
- генерации паролей,
- токенов безопасности
- ничего другого, когда нежелательно угадывание значения.
Идентификаторы, сгенерированные NewId, раскрывают личность машины, сгенерировавшей идентификатор (фактически, это её MAC-адрес), и время, когда она это сделала. Это может быть проблемой для некоторых чувствительных к безопасности приложений.
Источник: https://andrewlock.net/generating-sortable-guids-using-newid/
Генерация Сортируемых Guid с Помощью NewId. Окончание
Начало
NewId вместо полностью случайных Guid предоставляет UUID, который можно легко отсортировать. Рассмотрим простое приложение:
using MassTransit;Эта программа генерирует 5 идентификаторов. В результате получается что-то вроде этого:
foreach (var i in Enumerable.Range(0, 5))
{
NewId id = NewId.Next();
Console.WriteLine(id);
}
be170000-f32d-18db-de59-08da26f2ad5aНа первый взгляд может показаться, что все они одинаковы, но давайте разобьём первый экземпляр на 3 части:
be170000-f32d-18db-1816-08da26f2ad5b
be170000-f32d-18db-8694-08da26f2ad5b
be170000-f32d-18db-4dbd-08da26f2ad5b
be170000-f32d-18db-65b3-08da26f2ad5c
-
be170000-f32d-18db
— очевидно, это постоянное значение для всех идентификаторов.-
de59
— меняется с каждым ID.-
08da26f2ad5a
— иногда меняется, и меняется постепенно.NewId использует 3 разных источника для создания идентификатора:
1. ID машины/процесса – константа для данной машины (может быть настроена для включения идентификатора процесса).
2. Временную метку - обеспечивает базовый порядок идентификатора.
3. Последовательность - увеличивающийся идентификатор.
Объединив все 3 вместе, вы можете получить идентификатор, который (с натяжкой) упорядочен благодаря компоненту метки времени. Включив идентификатор рабочего процесса, вы можете заставить процессы генерировать независимые ID, избегая при этом коллизий. Это можно сделать, например, вызвав в начале программы:
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());А использование «последовательности» означает, что вы можете генерировать 2^16-1 идентификаторов в миллисекунду для каждого процесса/машины.
Очевидно, что такие ID приводят к гораздо менее фрагментированному индексу базы данных. Конечно, с идеально последовательными целыми числами они не сравнятся. Но сравнение индексов в оригинальной статье показало, что полностью случайные Guid приводят к почти 99% фрагментации индекса, тогда как фрагментация индекса NewId составляет лишь 5%.
Сгенерированные идентификаторы предсказуемы по своей сути. Их не следует использовать в сценариях, где желательна непредсказуемость. Эти идентификаторы НЕ должны использоваться для:
- генерации паролей,
- токенов безопасности
- ничего другого, когда нежелательно угадывание значения.
Идентификаторы, сгенерированные NewId, раскрывают личность машины, сгенерировавшей идентификатор (фактически, это её MAC-адрес), и время, когда она это сделала. Это может быть проблемой для некоторых чувствительных к безопасности приложений.
Источник: https://andrewlock.net/generating-sortable-guids-using-newid/
👍16
День 1286. #ЗаметкиНаПолях #AsyncTips
Реагирование на Запросы на Отмену Посредством Периодического Опроса
Задача: В коде имеется цикл, который должен поддерживать отмену.
Решение
Если в коде присутствует цикл обработки, то в нём нет низкоуровневых функций API, которым можно было передать
В большинстве случаев ваш код должен просто передать
У типа
Работа метода
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
Реагирование на Запросы на Отмену Посредством Периодического Опроса
Задача: В коде имеется цикл, который должен поддерживать отмену.
Решение
Если в коде присутствует цикл обработки, то в нём нет низкоуровневых функций API, которым можно было передать
CancellationToken
. В этом случае необходимо периодически проверять, не был ли отменён токен. Следующий пример периодически проверяет токен в ходе выполнения цикла, создающего вычислительную нагрузку на процессор:public int Cancelable(CancellationToken ct)Если тело цикла выполняется очень быстро, то, возможно, стоит ограничить частоту проверки токена отмены. Измерьте быстродействие до и после таких изменений, чтобы выбрать лучший вариант. Следующий пример похож на предыдущий, но выполняет больше итераций более быстрого цикла, поэтому добавлено ограничение на частоту проверки маркера:
{
for (int i = 0; i != 100; ++i)
{
Thread.Sleep(1000); // вычисления
ct.ThrowIfCancellationRequested();
}
return 42;
}
public int Cancelable(CancellationToken ct)Оптимальная частота опроса зависит исключительно от того, какой объём работы выполняется и насколько быстрой должна быть реакция на отмену.
{
for (int i = 0; i != 100000; ++i)
{
Thread.Sleep(1); // вычисления
if (i % 1000 == 0)
ct.ThrowIfCancellationRequested();
}
return 42;
}
В большинстве случаев ваш код должен просто передать
CancellationToken
на следующий уровень. Метод периодического опроса (polling), использованный в этом рецепте, следует применять только в том случае, если у вас имеется вычислительный цикл, который должен поддерживать отмену.У типа
CancellationToken
имеется другой метод IsCancellationRequested
, который начинает возвращать true при отмене токена. Некоторые разработчики используют его для реакции на отмену, обычно возвращая значение по умолчанию или null. В большинстве случаев использовать этот метод не рекомендуется. В стандартном паттерне отмены выдаётся исключение OperationCanceledException
, для чего вызывается метод ThrowIfCancellationRequested
. Если код, находящийся выше в стеке, захочет перехватить исключение и действовать так, словно результат равен null, это нормально, но любой код, получающий CancellationToken
, должен следовать стандартному паттерну отмены. Если вы решите не соблюдать паттерн отмены, по крайней мере чётко документируйте свои намерения.Работа метода
ThrowIfCancellationRequested
основана на периодическом опросе токена отмены; ваш код должен вызывать его с регулярными интервалами. Также существует способ регистрации обратного вызова, который вызывается при запросе на отмену. Об этом в будущих постах.Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
👍4
День 1287. #ЗаметкиНаПолях
Рекомендации по Обеспечению Безопасности Проектов на GitHub
Сегодня ПО подвержено постоянно меняющемуся набору угроз. Вот как вы можете защитить свои проекты на GitHub.
Средний проект на GitHub напрямую использует около 10 зависимостей с открытым исходным кодом. Это, наверное, неудивительно, но удивительно, что тот же репозиторий использует более 600 транзитивных зависимостей, которые получаются из 10 прямых зависимостей.
Огромное количество зависимостей, которые использует большинство проектов, означает, что если вы не используете автоматизацию для постоянного отслеживания уязвимостей и обновления, то, скорее всего, ваш проект уже уязвим. Хотя большинство уязвимостей в системе безопасности не являются злонамеренными, они возникают из-за случайных ошибок в коде, но они все же могут открыть дверь для злоумышленников, которые могут преследовать ваших пользователей или их данные.
GitHub предоставляет ряд встроенных инструментов, предназначенных для помощи в управлении деревом зависимостей, включая граф зависимостей и проверку зависимостей.
1. Для каждого репозитория граф зависимостей показывает зависимости, экосистемы и пакеты, на которых основана каждая зависимость. Граф зависимостей можно посмотреть на вкладке Insights вашего репозитория.
Подробнее про граф зависимостей.
2. Проверка зависимостей позволяет вам быстро просмотреть ваши зависимости. В рамках пул реквеста вы можете увидеть, что вы вводите, изменяете или удаляете, а также информацию об уязвимостях, лицензии и правилах использования. Проверка зависимостей даст вам:
- Информацию об уязвимостях в этой версии зависимости, а также её серьёзность и наличие более новой, исправленной версии.
- Информацию о лицензии для каждой зависимости.
Подробнее про проверку зависимостей.
3. При помощи Dependabot вы можете не только обнаруживать уязвимые зависимости, но и исправлять их. Он автоматически проверяет ваши файлы зависимостей на наличие устаревших зависимостей и открывает для каждой отдельный пул реквест. Затем он уведомляет вас и предлагает исправления, позволяя вам всегда работать с последними и наиболее безопасными выпусками.
Оповещения Dependabot можно включить как в общедоступных, так и в частных репозиториях. Вы также можете настроить уведомления, чтобы получать только те уведомления, которые вам нужны, и ничего больше. Кроме того, вы можете увидеть все оповещения, которые влияют на конкретный проект, на вкладке безопасности или в графе зависимостей.
Чтобы включить Dependabot, на главной странице репозитория под именем репозитория нажмите на вкладку Settings (Настройки). В левой боковой панели нажмите на Code security and analysis (Безопасность и анализ кода). На этой странице включите Dependency graph (Граф зависимостей), (Dependabot alerts) Предупреждения Dependabot и Dependabot security updates (Обновления безопасности Dependabot).
После этого GitHub предложит вам добавить файл dependabot.yml в папку
Источник: https://github.blog/2022-04-28-best-practices-to-keep-your-projects-secure-on-github/
Рекомендации по Обеспечению Безопасности Проектов на GitHub
Сегодня ПО подвержено постоянно меняющемуся набору угроз. Вот как вы можете защитить свои проекты на GitHub.
Средний проект на GitHub напрямую использует около 10 зависимостей с открытым исходным кодом. Это, наверное, неудивительно, но удивительно, что тот же репозиторий использует более 600 транзитивных зависимостей, которые получаются из 10 прямых зависимостей.
Огромное количество зависимостей, которые использует большинство проектов, означает, что если вы не используете автоматизацию для постоянного отслеживания уязвимостей и обновления, то, скорее всего, ваш проект уже уязвим. Хотя большинство уязвимостей в системе безопасности не являются злонамеренными, они возникают из-за случайных ошибок в коде, но они все же могут открыть дверь для злоумышленников, которые могут преследовать ваших пользователей или их данные.
GitHub предоставляет ряд встроенных инструментов, предназначенных для помощи в управлении деревом зависимостей, включая граф зависимостей и проверку зависимостей.
1. Для каждого репозитория граф зависимостей показывает зависимости, экосистемы и пакеты, на которых основана каждая зависимость. Граф зависимостей можно посмотреть на вкладке Insights вашего репозитория.
Подробнее про граф зависимостей.
2. Проверка зависимостей позволяет вам быстро просмотреть ваши зависимости. В рамках пул реквеста вы можете увидеть, что вы вводите, изменяете или удаляете, а также информацию об уязвимостях, лицензии и правилах использования. Проверка зависимостей даст вам:
- Информацию об уязвимостях в этой версии зависимости, а также её серьёзность и наличие более новой, исправленной версии.
- Информацию о лицензии для каждой зависимости.
Подробнее про проверку зависимостей.
3. При помощи Dependabot вы можете не только обнаруживать уязвимые зависимости, но и исправлять их. Он автоматически проверяет ваши файлы зависимостей на наличие устаревших зависимостей и открывает для каждой отдельный пул реквест. Затем он уведомляет вас и предлагает исправления, позволяя вам всегда работать с последними и наиболее безопасными выпусками.
Оповещения Dependabot можно включить как в общедоступных, так и в частных репозиториях. Вы также можете настроить уведомления, чтобы получать только те уведомления, которые вам нужны, и ничего больше. Кроме того, вы можете увидеть все оповещения, которые влияют на конкретный проект, на вкладке безопасности или в графе зависимостей.
Чтобы включить Dependabot, на главной странице репозитория под именем репозитория нажмите на вкладку Settings (Настройки). В левой боковой панели нажмите на Code security and analysis (Безопасность и анализ кода). На этой странице включите Dependency graph (Граф зависимостей), (Dependabot alerts) Предупреждения Dependabot и Dependabot security updates (Обновления безопасности Dependabot).
После этого GitHub предложит вам добавить файл dependabot.yml в папку
.github
вашего репозитория. В этом файле вам нужно будет настроить параметр package-ecosystem
- "nuget"
для проектов на .NET и schedule
> interval
– для желаемой частоты проверок.Источник: https://github.blog/2022-04-28-best-practices-to-keep-your-projects-secure-on-github/
👍5
DotNext возвращается!
В ноябре JUG Ru Group организует конференцию для .NET‑разработчиков — DotNext 2022 Autumn. В программе — технические доклады и дискуссии об архитектуре, производительности, безопасности, фреймворках и инструментах.
Участники конференции любят обсуждать нетривиальные задачи и новые подходы в .NET‑разработке. И если вам есть что сказать, тогда подавайте заявку на выступление: https://bit.ly/3zDv3Zk
Программный комитет поможет с подготовкой к выступлению: назначит персонального куратора, проведет ревью материала и организует репетиции.
Выбирайте тему выступления на сайте или предлагайте свои идеи — их обязательно рассмотрят.
Всем спикерам JUG Ru Group дарит билет на все конференции сезона в онлайне и офлайне.
А билеты можно купить здесь: https://bit.ly/3Qdd5np
В ноябре JUG Ru Group организует конференцию для .NET‑разработчиков — DotNext 2022 Autumn. В программе — технические доклады и дискуссии об архитектуре, производительности, безопасности, фреймворках и инструментах.
Участники конференции любят обсуждать нетривиальные задачи и новые подходы в .NET‑разработке. И если вам есть что сказать, тогда подавайте заявку на выступление: https://bit.ly/3zDv3Zk
Программный комитет поможет с подготовкой к выступлению: назначит персонального куратора, проведет ревью материала и организует репетиции.
Выбирайте тему выступления на сайте или предлагайте свои идеи — их обязательно рассмотрят.
Всем спикерам JUG Ru Group дарит билет на все конференции сезона в онлайне и офлайне.
А билеты можно купить здесь: https://bit.ly/3Qdd5np
👍5
День 1288. #TypesAndLanguages
6. Запрещать или Разрешать при Разработке ПО
Дискуссии в области разработки ПО довольно часто касаются личных предпочтений. Несмотря на то, что все участники дебатов спорят, основываясь на своих знаниях, навыках или опыте, их дискуссии довольно часто сводятся к вопросу вкуса и цвета.
Одним из примеров является спор «Открытое Наследование или Разрешённое Наследование» Мартина Фаулера. Вопрос в том, должны ли мы по умолчанию разрешать наследование класса или блокировать его. Мы можем привести множество аргументов за и против, но нет единого показателя, показывающего, какой подход лучше. То же самое относится к тому, чтобы сделать методы виртуальными или запечатанными по умолчанию. Или о том, насколько всё делать приватным или открытым. Эти дискуссии, как правило, основаны на личном ощущении участников дебатов, и может быть довольно занимательно узнавать аргументацию, стоящую за каждым из вариантов.
Возьмем отрешённый пример. Представьте, что вы возвращаетесь домой ночью, в темном переулке, и тут появляются какие-то люди, бьют вас, забирают телефон и исчезают. Как правило, после такой ситуации вы можете использовать три разных подхода:
1. Вы решаете избегать таких встреч, насколько это возможно. Вы не возвращаетесь домой ночью, избегаете темных переулков или даже остаётесь дома. По сути, вы заставляете себя избегать проблемы.
2. Вы утверждаете, что такой ситуации быть не должно, что полиция должна быть ночью на улице, чтобы помочь вам в таком случае. Вы заставляете других сделать так, чтобы такая ситуация больше не повторилась.
3. Вы также можете пойти в спортзал, научиться боксу или боевым искусствам или носить оружие, чтобы в следующий раз быть готовым и не дать им забрать ваш телефон. По сути, вы заставляете себя принять ситуацию.
Вам решать, какой вариант вы выберете. Хотя вы можете возразить, что некоторые из них невыполнимы в вашем случае или нежелательны.
То же самое относится и к разработке ПО. Допустим, вы нашли ошибку в длинной функции, меняющей состояние приложения. Что вы сделаете? Варианты:
1. Вы решаете, что вы и ваша команда больше не будете так писать. Вы делаете акцент на обзорах кода, чтобы не пропускать такие функции.
2. Вы решаете, что такие функции вообще нельзя разрешать. Вы меняете свой стек на использование чистых функций (например, на F# или Haskell).
3. Вы просто улучшаете свои навыки, чтобы лучше поддерживать длинные функции, меняющие состояние приложения.
Похоже, что индустрия обычно выбирает первый вариант. В сети можно много прочитать о «чистом коде». Такие принципы, как «метод должен иметь не более двух параметров», подкрепляются такими утверждениями, как «Я работаю в отрасли уже 30 лет, поэтому я знаю лучше». Однако в итоге это просто вопрос личных предпочтений. На предпочтение могут влиять когнитивные навыки, окружающая среда, опыт, мастерство, риск, стоимость и, возможно, многие другие причины. Однако нет метрик, показывающих, что «контейнеры DI — это плохо» (как говорят Java-программисты, в то время как .NET-программисты получают поддержку DI «из коробки» в .NET Core), «функции должны иметь длину не более 10 строк» (а затем вы видите, что пул реквесты в коде ядра Linux делают совершенно по-другому), или «чистые функции лучше, чем нечистые» (а затем вы заворачиваете свой код в морской узел, чтобы создать конечный автомат без состояния в нём).
Должны ли мы запрещать или разрешать? Я склоняюсь к последнему. Но опять же, это вопрос предпочтений.
Источник: https://blog.adamfurmanek.pl/2022/07/16/types-and-programming-languages-part-15/
6. Запрещать или Разрешать при Разработке ПО
Дискуссии в области разработки ПО довольно часто касаются личных предпочтений. Несмотря на то, что все участники дебатов спорят, основываясь на своих знаниях, навыках или опыте, их дискуссии довольно часто сводятся к вопросу вкуса и цвета.
Одним из примеров является спор «Открытое Наследование или Разрешённое Наследование» Мартина Фаулера. Вопрос в том, должны ли мы по умолчанию разрешать наследование класса или блокировать его. Мы можем привести множество аргументов за и против, но нет единого показателя, показывающего, какой подход лучше. То же самое относится к тому, чтобы сделать методы виртуальными или запечатанными по умолчанию. Или о том, насколько всё делать приватным или открытым. Эти дискуссии, как правило, основаны на личном ощущении участников дебатов, и может быть довольно занимательно узнавать аргументацию, стоящую за каждым из вариантов.
Возьмем отрешённый пример. Представьте, что вы возвращаетесь домой ночью, в темном переулке, и тут появляются какие-то люди, бьют вас, забирают телефон и исчезают. Как правило, после такой ситуации вы можете использовать три разных подхода:
1. Вы решаете избегать таких встреч, насколько это возможно. Вы не возвращаетесь домой ночью, избегаете темных переулков или даже остаётесь дома. По сути, вы заставляете себя избегать проблемы.
2. Вы утверждаете, что такой ситуации быть не должно, что полиция должна быть ночью на улице, чтобы помочь вам в таком случае. Вы заставляете других сделать так, чтобы такая ситуация больше не повторилась.
3. Вы также можете пойти в спортзал, научиться боксу или боевым искусствам или носить оружие, чтобы в следующий раз быть готовым и не дать им забрать ваш телефон. По сути, вы заставляете себя принять ситуацию.
Вам решать, какой вариант вы выберете. Хотя вы можете возразить, что некоторые из них невыполнимы в вашем случае или нежелательны.
То же самое относится и к разработке ПО. Допустим, вы нашли ошибку в длинной функции, меняющей состояние приложения. Что вы сделаете? Варианты:
1. Вы решаете, что вы и ваша команда больше не будете так писать. Вы делаете акцент на обзорах кода, чтобы не пропускать такие функции.
2. Вы решаете, что такие функции вообще нельзя разрешать. Вы меняете свой стек на использование чистых функций (например, на F# или Haskell).
3. Вы просто улучшаете свои навыки, чтобы лучше поддерживать длинные функции, меняющие состояние приложения.
Похоже, что индустрия обычно выбирает первый вариант. В сети можно много прочитать о «чистом коде». Такие принципы, как «метод должен иметь не более двух параметров», подкрепляются такими утверждениями, как «Я работаю в отрасли уже 30 лет, поэтому я знаю лучше». Однако в итоге это просто вопрос личных предпочтений. На предпочтение могут влиять когнитивные навыки, окружающая среда, опыт, мастерство, риск, стоимость и, возможно, многие другие причины. Однако нет метрик, показывающих, что «контейнеры DI — это плохо» (как говорят Java-программисты, в то время как .NET-программисты получают поддержку DI «из коробки» в .NET Core), «функции должны иметь длину не более 10 строк» (а затем вы видите, что пул реквесты в коде ядра Linux делают совершенно по-другому), или «чистые функции лучше, чем нечистые» (а затем вы заворачиваете свой код в морской узел, чтобы создать конечный автомат без состояния в нём).
Должны ли мы запрещать или разрешать? Я склоняюсь к последнему. Но опять же, это вопрос предпочтений.
Источник: https://blog.adamfurmanek.pl/2022/07/16/types-and-programming-languages-part-15/
👍10
День 1289. #ЗаметкиНаПолях
Хранение Динамических Данных с Помощью EF Core. Начало
Рассмотрим, как можно хранить «динамические» пользовательские данные с помощью Entity Framework Core. Динамические в том смысле, что вы можете не знать, какими будут пары данных ключ/значение, но их по-прежнему важно сохранить. На ум приходят два способа, каждый со своими преимуществами и недостатками. Сегодня рассмотрим первый.
1. Использование сериализации/десериализации JSON
В Entity Framework Core вы можете использовать методы преобразования для сериализации данных при записи в базу данных и десериализации данных при чтении из таблицы.
Преимущества такого подхода:
- меньшая сложность в разработке схемы базы данных (просто ещё один столбец),
- быстрые чтение и запись.
Недостатки:
- сериализация/десериализация может быть дорогостоящей,
- вы либо получаете все пользовательские значения, либо ничего (нельзя выбрать, какие значения возвращаются в запросе).
Настройка
Во-первых, определим объект для хранения:
Следующий шаг — настроить преобразование как часть конфигурации EF Core. Здесь используется SQLite, но это должно работать с любой реляционной базой данных, которая может хранить текст в столбце.
Источник: https://khalidabuhakmeh.com/storing-dynamic-user-data-with-ef-core
Хранение Динамических Данных с Помощью EF Core. Начало
Рассмотрим, как можно хранить «динамические» пользовательские данные с помощью Entity Framework Core. Динамические в том смысле, что вы можете не знать, какими будут пары данных ключ/значение, но их по-прежнему важно сохранить. На ум приходят два способа, каждый со своими преимуществами и недостатками. Сегодня рассмотрим первый.
1. Использование сериализации/десериализации JSON
В Entity Framework Core вы можете использовать методы преобразования для сериализации данных при записи в базу данных и десериализации данных при чтении из таблицы.
Преимущества такого подхода:
- меньшая сложность в разработке схемы базы данных (просто ещё один столбец),
- быстрые чтение и запись.
Недостатки:
- сериализация/десериализация может быть дорогостоящей,
- вы либо получаете все пользовательские значения, либо ничего (нельзя выбрать, какие значения возвращаются в запросе).
Настройка
Во-первых, определим объект для хранения:
public class Entity
{
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
= DateTime.UtcNow;
public Dictionary<string, string>
Values { get; set; } = new();
}
Dictionary<string,string>
выбран ради простоты использования с System.Text.Json, в котором нет конвертера для Dictionary<string,object>
. Хотя конвертер можно написать, как это сделал Йозеф Оттоссон в своем блоге.Следующий шаг — настроить преобразование как часть конфигурации EF Core. Здесь используется SQLite, но это должно работать с любой реляционной базой данных, которая может хранить текст в столбце.
public class Database : DbContextДля использования в коде, как и в любом словаре, нам нужно только предоставить словарю пару ключ/значение:
{
public DbSet<Entity> Entity { get; set; }
protected override void
OnModelCreating(ModelBuilder mb)
{
var opts = new JsonSerializerOptions(
JsonSerializerDefaults.General);
mb.Entity<Entity>()
.Property(x => x.Values)
.HasColumnName("Values")
.HasColumnType("BLOB")
.HasConversion(
v => JsonSerializer.Serialize(v, options),
s => JsonSerializer
.Deserialize<Dictionary<string, string>>(s, options),
ValueComparer.CreateDefault(
typeof(Dictionary<string, string>), true)
);
}
}
var json = new EntityОкончание следует…
{
Values = new()
{
{"Name", "Dotnet"},
{"Status", "Awesome"}
}
};
Источник: https://khalidabuhakmeh.com/storing-dynamic-user-data-with-ef-core
👍7
День 1290. #ЗаметкиНаПолях
Хранение Динамических Данных с Помощью EF Core. Окончание
Начало
2. Хранение пользовательских данных в инвертированной таблице
Инвертированные таблицы — это когда мы храним пары ключ/значение в отдельных строках. В этом случае ключи и значения становятся столбцами, что обеспечивает гибкость.
Преимущества такого подхода:
- Мы можем хранить «бесконечное» количество пользовательских данных.
- Мы можем отфильтровать отдельные строки, чтобы получить одно значение.
- Мы можем реализовать логику уникальности ключей для каждой сущности.
Недостатки:
- Столбцы значений должны иметь строгий тип, скорее всего строковый тип.
- Эти таблицы могут быстро расти в зависимости от объема пользовательских данных.
Настройка
Настройка инвертированной таблицы не отличается от типичных отношений «один ко многим».
Посмотрим, как сохранить эти пользовательские значения:
Хранение Динамических Данных с Помощью EF Core. Окончание
Начало
2. Хранение пользовательских данных в инвертированной таблице
Инвертированные таблицы — это когда мы храним пары ключ/значение в отдельных строках. В этом случае ключи и значения становятся столбцами, что обеспечивает гибкость.
Преимущества такого подхода:
- Мы можем хранить «бесконечное» количество пользовательских данных.
- Мы можем отфильтровать отдельные строки, чтобы получить одно значение.
- Мы можем реализовать логику уникальности ключей для каждой сущности.
Недостатки:
- Столбцы значений должны иметь строгий тип, скорее всего строковый тип.
- Эти таблицы могут быстро расти в зависимости от объема пользовательских данных.
Настройка
Настройка инвертированной таблицы не отличается от типичных отношений «один ко многим».
public class EntityМетод
{
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
= DateTime.UtcNow;
public ICollection<Values> Values { get; set; }
= new List<Values>();
public Entity AddValue(string name, string value)
{
var existing = Values?.
FirstOrDefault(v => v.Name.Equals(name));
if (existing is { })
existing.Value = value;
else
Values?.Add(
new Values {Name = name, Value = value}
);
return this;
}
}
public class Values
{
public int Id { get; set; }
public int EntityId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
AddValue
в типе Entity
будет работать с оговоркой, что у вас есть все значения из связанной таблицы Values
в памяти. Если нет, вы получите повторяющиеся пары ключ/значение в своей коллекции.Посмотрим, как сохранить эти пользовательские значения:
var invertedTable = new Entity()Разница с первым методом в том, что подход с инвертированной таблицей требует включения значений при чтении сущностей из базы данных:
.AddValue("Name", "Dotnet")
.AddValue("Status", "Awesome");
var invertedTable = dbВызов
.EntityWithInvertedTables
.OrderByDescending(o => o.CreatedAt)
.Include(x => x.Values)
.First();
Include
загрузит все значения из связанной таблицы. Хотя, вы можете загрузить только нужные значения (но помните, что в этом случае метод сущности AddValue
перестанет корректно работать):…Источник: https://khalidabuhakmeh.com/storing-dynamic-user-data-with-ef-core
.Include(x => x.Values.Where(v => v.Name == "Name"))
.First();
👍3
День 1291. #ЧтоНовенького
Миграция из ASP.NET в ASP.NET Core в Visual Studio
Я уже писал про экспериментальное расширение для Visual Studio Microsoft Project Migrations, которое позволяет обновить ваши проекты ASP.NET на ASP.NET Core. Сегодня подробнее про процесс обновления.
Это ранний экспериментальный выпуск, поэтому вы можете столкнуться с некоторыми проблемами. Расширение помогает в процессе миграции, но по-прежнему требуются шаги по ручной миграции, включая устранение оставшихся ошибок компиляции и времени выполнения. Со временем количество ошибок будет уменьшаться.
В Visual Studio после установки расширения щёлкните правой кнопкой на проект и выберите Migrate Project. При этом
- Новый проект ASP.NET Core создаётся и добавляется в решение.
- Проект ASP.NET Core уже настроен с помощью YARP как прокси для передачи запросов исходному проекту ASP.NET.
- Оба проекта будут настроены как стартовые проекты.
Процесс создания нового проекта показан в видео ниже.
Теперь вы можете начать перенос отдельных элементов из проекта ASP.NET в проект ASP.NET Core. В настоящее время расширение поддерживает миграцию: контроллеров, представлений и классов. Для этого щелкните на элементе правой кнопкой и выберите команду Migrate. Расширение проанализирует выбранный элемент, чтобы определить, от каких элементов он зависит, и также попытается перенести их. Попутно могут обнаружиться элементы, которые невозможно перенести автоматически, их необходимо будет перенести вручную. При этом вы можете снять галочки с зависимостей, если хотите пропустить их миграцию. Позже можно повторно запустить миграцию элемента, чтобы перенести дополнительные или ранее пропущенные зависимости. При повторном запуске миграции будут пропущены все элементы, которые уже были перенесены.
После выполнения миграции будет показан список затронутых элементов со статусом переноса:
- элемент был успешно перенесен,
- элемент был пропущен,
- было выдано предупреждение,
- произошла ошибка.
В окне Output содержится дополнительная информация о каждом выполненном шаге. Элементы могут быть пропущены по нескольким причинам, в том числе: элемент был перенесён ранее, элемент не поддерживается для переноса, нет известных действий для переноса выбранного элемента и по другим причинам.
Инструмент миграции не удаляет перенесённый контент, это нужно сделать вам, если вы уверены, что процесс прошёл успешно и вы довольны результатами. Когда в приложение поступает запрос, он сначала направляется в проект Core. Если новый проект содержит контроллер для этого маршрута, проект Core ответит на запрос. Если нет, передаст его старому проекту.
Известные проблемы
Расширение всё ещё на раннем этапе разработки, и в текущей версии существуют различные известные проблемы и ограничения. Вот что на данный момент не поддерживается:
- Файлы веб-контента (например, CSS/JS и т. д.) не переносятся.
- Классы, использующие Entity Framework.
- Файлы, связанные с .NET Identity.
- Проекты библиотек классов .NET Framework.
- Представления веб-форм ASP.NET.
- Миграция представлений Razor в настоящее время очень ограничена; в настоящее время нет поддержки частичных представлений или файлов layout.
- Области ASP.NET MVC.
Источник: https://devblogs.microsoft.com/dotnet/introducing-project-migrations-visual-studio-extension/
Миграция из ASP.NET в ASP.NET Core в Visual Studio
Я уже писал про экспериментальное расширение для Visual Studio Microsoft Project Migrations, которое позволяет обновить ваши проекты ASP.NET на ASP.NET Core. Сегодня подробнее про процесс обновления.
Это ранний экспериментальный выпуск, поэтому вы можете столкнуться с некоторыми проблемами. Расширение помогает в процессе миграции, но по-прежнему требуются шаги по ручной миграции, включая устранение оставшихся ошибок компиляции и времени выполнения. Со временем количество ошибок будет уменьшаться.
В Visual Studio после установки расширения щёлкните правой кнопкой на проект и выберите Migrate Project. При этом
- Новый проект ASP.NET Core создаётся и добавляется в решение.
- Проект ASP.NET Core уже настроен с помощью YARP как прокси для передачи запросов исходному проекту ASP.NET.
- Оба проекта будут настроены как стартовые проекты.
Процесс создания нового проекта показан в видео ниже.
Теперь вы можете начать перенос отдельных элементов из проекта ASP.NET в проект ASP.NET Core. В настоящее время расширение поддерживает миграцию: контроллеров, представлений и классов. Для этого щелкните на элементе правой кнопкой и выберите команду Migrate. Расширение проанализирует выбранный элемент, чтобы определить, от каких элементов он зависит, и также попытается перенести их. Попутно могут обнаружиться элементы, которые невозможно перенести автоматически, их необходимо будет перенести вручную. При этом вы можете снять галочки с зависимостей, если хотите пропустить их миграцию. Позже можно повторно запустить миграцию элемента, чтобы перенести дополнительные или ранее пропущенные зависимости. При повторном запуске миграции будут пропущены все элементы, которые уже были перенесены.
После выполнения миграции будет показан список затронутых элементов со статусом переноса:
- элемент был успешно перенесен,
- элемент был пропущен,
- было выдано предупреждение,
- произошла ошибка.
В окне Output содержится дополнительная информация о каждом выполненном шаге. Элементы могут быть пропущены по нескольким причинам, в том числе: элемент был перенесён ранее, элемент не поддерживается для переноса, нет известных действий для переноса выбранного элемента и по другим причинам.
Инструмент миграции не удаляет перенесённый контент, это нужно сделать вам, если вы уверены, что процесс прошёл успешно и вы довольны результатами. Когда в приложение поступает запрос, он сначала направляется в проект Core. Если новый проект содержит контроллер для этого маршрута, проект Core ответит на запрос. Если нет, передаст его старому проекту.
Известные проблемы
Расширение всё ещё на раннем этапе разработки, и в текущей версии существуют различные известные проблемы и ограничения. Вот что на данный момент не поддерживается:
- Файлы веб-контента (например, CSS/JS и т. д.) не переносятся.
- Классы, использующие Entity Framework.
- Файлы, связанные с .NET Identity.
- Проекты библиотек классов .NET Framework.
- Представления веб-форм ASP.NET.
- Миграция представлений Razor в настоящее время очень ограничена; в настоящее время нет поддержки частичных представлений или файлов layout.
- Области ASP.NET MVC.
Источник: https://devblogs.microsoft.com/dotnet/introducing-project-migrations-visual-studio-extension/
👍4
День 1293. #Оффтоп #МоиИнструменты
Notebook Editor для Visual Studio
Сегодня посоветую вам видео Скотта Хенсельмана https://youtu.be/WfozTizHMlM, в котором он рассказывает про расширение Jupiter Notebooks для Visual Studio.
Jupiter Notebooks – это смесь документа Word со средой исполнения. Если вам нужно научить кого-то языку, новому функционалу, попросить кандидата на интервью выполнить задание, либо просто описать, какие действия нужно сделать в программе. Вместо того, чтобы писать всё это в текстовом документе, откуда куски кода придётся копировать и вставлять в среду исполнения, используйте Jupiter Notebooks, где можно исполнять код прямо в документе.
Скотт рассказывает про инструмент на примере обучающих курсов от Microsoft по C# и Machine Learning.
На GitHub есть репозиторий с примерами использования https://github.com/dotnet/csharp-notebooks/
Источник: https://techcommunity.microsoft.com/t5/educator-developer-blog/using-visual-studio-notebooks-for-learning-c/ba-p/3580015
Notebook Editor для Visual Studio
Сегодня посоветую вам видео Скотта Хенсельмана https://youtu.be/WfozTizHMlM, в котором он рассказывает про расширение Jupiter Notebooks для Visual Studio.
Jupiter Notebooks – это смесь документа Word со средой исполнения. Если вам нужно научить кого-то языку, новому функционалу, попросить кандидата на интервью выполнить задание, либо просто описать, какие действия нужно сделать в программе. Вместо того, чтобы писать всё это в текстовом документе, откуда куски кода придётся копировать и вставлять в среду исполнения, используйте Jupiter Notebooks, где можно исполнять код прямо в документе.
Скотт рассказывает про инструмент на примере обучающих курсов от Microsoft по C# и Machine Learning.
На GitHub есть репозиторий с примерами использования https://github.com/dotnet/csharp-notebooks/
Источник: https://techcommunity.microsoft.com/t5/educator-developer-blog/using-visual-studio-notebooks-for-learning-c/ba-p/3580015
YouTube
Visual Studio Notebook Editor brings C# and .NET to Jupyter Notebooks - Learn To Code Interactively
Visual Studio Notebook Editor brings C# and .NET to Jupyter Notebooks - Learn To Code Interactively. Also Machine Learning and AI!
Install Notebook Editor Extension:
https://marketplace.visualstudio.com/items?itemName=MLNET.notebook
C# Notebooks Repo:…
Install Notebook Editor Extension:
https://marketplace.visualstudio.com/items?itemName=MLNET.notebook
C# Notebooks Repo:…
👍2
День 1294. #ЗаметкиНаПолях #AsyncTips
Отмена по тайм-ауту
Тайм-аут — всего лишь одна из разновидностей запроса на отмену. Код, который необходимо отменить, просто отслеживает токен отмены, как и при любой другой отмене; ему не нужно знать, что источником отмены является таймер. У источников токенов отмены существуют вспомогательные методы, которые автоматически выдают запрос на отмену по тайм-ауту:
Многие асинхронные API поддерживают CancellationToken, поэтому обеспечение отмены обычно сводится к простой передаче токена. Как правило, если ваш метод вызывает функции API, получающие CancellationToken, то ваш метод также должен получать CancellationToken и передавать его всем функциям API, которые его поддерживают.
К сожалению, некоторые методы не поддерживают отмену. В такой ситуации простого решения не существует. Невозможно безопасно остановить произвольный код, если только он не упакован в отдельный исполняемый модуль. Если ваш код вызывает код, не поддерживающий отмену и вы не хотите упаковывать этот код в отдельный исполняемый модуль, всегда можно имитировать отмену, просто игнорируя результат.
Отмена должна предоставляться как вариант там, где это возможно. Дело в том, что правильно реализованная отмена на высоком уровне зависит от правильно реализованной отмены на нижнем уровне. Таким образом, когда вы пишете собственные async-методы, постарайтесь как можно тщательнее обеспечить поддержку отмены. Никогда неизвестно заранее, какие высокоуровневые методы будут вызывать ваш код, и им тоже может понадобиться отмена.
Отмена параллельного кода
Простейший способ поддержки отмены — передача CancellationToken параллельному коду через ParallelOptions:
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
Отмена по тайм-ауту
Тайм-аут — всего лишь одна из разновидностей запроса на отмену. Код, который необходимо отменить, просто отслеживает токен отмены, как и при любой другой отмене; ему не нужно знать, что источником отмены является таймер. У источников токенов отмены существуют вспомогательные методы, которые автоматически выдают запрос на отмену по тайм-ауту:
using var cts = new CancellationTokenSource();Кроме того, тайм-аут можно передать конструктору:
cts.CancelAfter(TimeSpan.FromSeconds(5));
async Task IssueTimeoutAsync()Отмена async-кода
{
using var cts = new CancellationTokenSource(
TimeSpan.FromSeconds(5));
var token = cts.Token;
await Task.Delay(TimeSpan.FromSeconds(10), token);
}
Многие асинхронные API поддерживают CancellationToken, поэтому обеспечение отмены обычно сводится к простой передаче токена. Как правило, если ваш метод вызывает функции API, получающие CancellationToken, то ваш метод также должен получать CancellationToken и передавать его всем функциям API, которые его поддерживают.
К сожалению, некоторые методы не поддерживают отмену. В такой ситуации простого решения не существует. Невозможно безопасно остановить произвольный код, если только он не упакован в отдельный исполняемый модуль. Если ваш код вызывает код, не поддерживающий отмену и вы не хотите упаковывать этот код в отдельный исполняемый модуль, всегда можно имитировать отмену, просто игнорируя результат.
Отмена должна предоставляться как вариант там, где это возможно. Дело в том, что правильно реализованная отмена на высоком уровне зависит от правильно реализованной отмены на нижнем уровне. Таким образом, когда вы пишете собственные async-методы, постарайтесь как можно тщательнее обеспечить поддержку отмены. Никогда неизвестно заранее, какие высокоуровневые методы будут вызывать ваш код, и им тоже может понадобиться отмена.
Отмена параллельного кода
Простейший способ поддержки отмены — передача CancellationToken параллельному коду через ParallelOptions:
void Rotate(В Parallel LINQ (PLINQ) также предусмотрена встроенная поддержка отмены с оператором WithCancellation:
IEnumerable<Matrix> matrices,
float degrees,
CancellationToken ct)
{
Parallel.ForEach(matrices,
new ParallelOptions { CancellationToken = ct },
m => m.Rotate(degrees));
}
IEnumerable<int> MultiplyBy2(Поддержка отмены для параллельной работы — важный критерий хорошего пользовательского интерфейса. Если ваше приложение выполняет параллельную работу, оно создает серьезную нагрузку на процессор пусть даже на короткое время. Высокий уровень использования процессора обычно заметен для пользователей, даже если не мешает работе других приложений на той же машине.
IEnumerable<int> values,
CancellationToken ct)
{
return values.AsParallel()
.WithCancellation(ct)
.Select(item => item * 2);
}
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
👍10
День 1295. #ЧтоНовенького #CSharp11
Обзор Новинок C# 11. Начало
C# 11 должен выйти ноябре 2022 года вместе с .NET 7. Рассмотрим новые функции, которые обещают выпустить в новой версии языка.
Эти функции все ещё находятся в стадии превью и, возможно, не все войдут в окончательный выпуск C# 11.
Попробовать новые функции можно в Visual Studio 2022 (версия 17.3.0 или выше). Также необходимо загрузить .NET 7 SDK (версия 7.0.0 preview 6 или выше). Кроме того, в функциях предварительного просмотра IDE нужно включить Use previews of the .NET SDK (Предварительный просмотр .NET SDK).
1. Обязательные члены
Модификатор required можно использовать для свойства, чтобы убедиться, что мы явно устанавливаем значение при инициализации объекта.
2. Структуры со значениями по умолчанию
В C# 10 нам приходилось явно устанавливать значения по умолчанию для каждого из его членов при добавлении в структуру конструктора:
3. Необработанные строковые литералы
Использование строк, содержащих кавычки, или ссылки на фрагменты кода, такие как JSON, стало намного проще. Раньше приходилось экранировать кавычки обратной косой чертой.
Необработанные строковые литералы начинаются и заканчиваются тремя кавычками
Также можно интерполировать с помощью знака
Окончание следует…
Источник: https://www.roundthecode.com/dotnet/c-sharp-11-preview-features-dotnet-7
Обзор Новинок C# 11. Начало
C# 11 должен выйти ноябре 2022 года вместе с .NET 7. Рассмотрим новые функции, которые обещают выпустить в новой версии языка.
Эти функции все ещё находятся в стадии превью и, возможно, не все войдут в окончательный выпуск C# 11.
Попробовать новые функции можно в Visual Studio 2022 (версия 17.3.0 или выше). Также необходимо загрузить .NET 7 SDK (версия 7.0.0 preview 6 или выше). Кроме того, в функциях предварительного просмотра IDE нужно включить Use previews of the .NET SDK (Предварительный просмотр .NET SDK).
1. Обязательные члены
Модификатор required можно использовать для свойства, чтобы убедиться, что мы явно устанавливаем значение при инициализации объекта.
public class RequiredMemberКогда мы инициализируем объект, мы должны убедиться, что мы установили значение для этого свойства. В противном случае будет выдана ошибка компиляции:
{
public required string Name { get; set; }
}
var requiredMember = new RequiredMember { Name = "Dave" };Также возможно установить обязательный член внутри конструктора объекта. Однако мы должны добавить атрибут. Если мы просто установим требуемое свойство через параметр, это вызовет ошибку компиляции при вызове такого конструктора. Нужно установить атрибут
[SetsRequiredMembers]
над конструктором. Это сообщает компилятору, что мы устанавливаем необходимые элементы внутри конструктора:public class RequiredMemberЧто интересно, установка атрибута отменяет требование собственно установки значения свойства, и ошибки при этом не возникнет.
{
public required string Name { get; set; }
[SetsRequiredMembers]
public RequiredMember(string name)
{
Name = name;
}
}
2. Структуры со значениями по умолчанию
В C# 10 нам приходилось явно устанавливать значения по умолчанию для каждого из его членов при добавлении в структуру конструктора:
public struct AutoDefaultStructЕсли бы мы не установили свойство
{
public int Number { get; set; }
public AutoDefaultStruct()
{
Number = 0;
}
}
Number
в конструкторе, это вызвало бы ошибку компиляции. В C# 11 если эти элементы не заданы в конструкторе, для них будут установлены значения по умолчанию. В данном случае для Number будет установлено значение 0.3. Необработанные строковые литералы
Использование строк, содержащих кавычки, или ссылки на фрагменты кода, такие как JSON, стало намного проще. Раньше приходилось экранировать кавычки обратной косой чертой.
Необработанные строковые литералы начинаются и заканчиваются тремя кавычками
"""..."""
. Теперь кавычки теперь будут рассматриваться как часть строки.Также можно интерполировать с помощью знака
$
. Количество знаков $
, предваряемых строкой, представляет собой количество фигурных скобок, необходимых для ссылки на переменную:public class RawStringLiteralВ примере выше использованы два знака
{
public static int MyNumber = 1;
public string MyJsonString =
$$"""
{
"number": "{{MyNumber}}"
}
""";
}
$
в начале, поэтому нужно включить две фигурные скобки, чтобы указать переменную, на которую мы хотим сослаться.Окончание следует…
Источник: https://www.roundthecode.com/dotnet/c-sharp-11-preview-features-dotnet-7
👍10
Что сделает следующий код?
string[] names = null;
foreach(var name in names) Console.WriteLine(name.Length); #Quiz #CSharp
string[] names = null;
foreach(var name in names) Console.WriteLine(name.Length); #Quiz #CSharp
Anonymous Quiz
16%
Ничего не выведет, потому что в names нет элементов
18%
Выбросит исключение на строке 1, потому что массивы должны быть инициализированы
58%
Выбросит исключение на строке 2, потому что нельзя перечислять null
8%
Выбросит исключение на строке 3, потому что нельзя вызывать свойства у null
👍14
День 1296. #ЧтоНовенького #CSharp11
Обзор Новинок C# 11. Окончание
Начало
4. Обобщённые атрибуты
До C# 11 передача типа в атрибут требовала параметра типа Type и передачи значения через typeof
Шаблоны списков позволяют сопоставлять шаблоны для элементов массива или списка. Здесь у нас есть несколько вариантов.
При явном указании значений массив должен будет строго соответствовать шаблону:
Символ пустой переменной
Источник: https://www.roundthecode.com/dotnet/c-sharp-11-preview-features-dotnet-7
Обзор Новинок C# 11. Окончание
Начало
4. Обобщённые атрибуты
До C# 11 передача типа в атрибут требовала параметра типа Type и передачи значения через typeof
[MyAttr(typeof(string))]Теперь можно делать обобщённые атрибуты:
public class MyAttr<T> : Attribute { }Единственное ограничение, что это должен быть полностью сконструированный тип. Попытка использовать в атрибуте параметр типа обобщённого класса приведёт к ошибке компиляции:
…
[MyAttr<string>]
public class MyAttr<T> : Attribute { }5. Шаблоны списков
public class MyClass<T>
{
[MyAttr<T>] // Ошибка компиляции
public MyClass()
{
}
}
Шаблоны списков позволяют сопоставлять шаблоны для элементов массива или списка. Здесь у нас есть несколько вариантов.
При явном указании значений массив должен будет строго соответствовать шаблону:
public bool Is_1_3_5(int[] numbers)
{
return numbers is [1, 3, 5];
// numbers должен быть длиной 3
// и иметь элементы 1, 3 и 5
}
Символ пустой переменной
_
соответствует единичному элементу с любым значением:numbers is [1, _, 5];Две точки
// numbers должен быть длиной 3
// и иметь элементы 1, <любое целое число> и 5
..
будут соответствовать 0 или более элементов:numbers is [1, .., 5];Также можно указать, что значение может быть больше или меньше определённого:
// numbers может быть любой длины
// должен начинаться с 1 и заканчиваться 5
numbers is [1, .., >=5];Как видите, шаблоны дают нам множество вариантов проверки элементов списка или массива.
// numbers может быть любой длины
// должен начинаться с 1
// и заканчиваться числом не меньше 5
Источник: https://www.roundthecode.com/dotnet/c-sharp-11-preview-features-dotnet-7
👍13
День 1297. #Юмор #CodeReview
Обзор Кода: Как Нажить Себе Врагов
Иногда люди на работе раздражают вас, и вы чувствуете, что нужно отыграться. Если вы разрабатываете ПО, то способ есть – обзор кода! Это фантастический способ отомстить с помощью пассивно-агрессивных действий.
Проверяющий
1. Комментарии о стиле кода
У большинства компаний есть рекомендации по стилю кода. Изучите их! А затем начните просить об изменениях, которые явно не упомянуты. Если в рекомендациях по стилю кода что-то не упоминается, то это отличный шанс попросить внести бессмысленные изменения, которые просто заставят вашу жертву поработать:
- Правильно ли названы методы в классе модульного теста?
- Не слишком ли многословно названа переменная?
- Не используется синтаксис Йоды? Попросите изменить условия на противоположные.
2. Попросите об изменениях, которые не имеют смысла
Шаг 1 раздражает, но сам по себе он не смертелен. Нужно продолжать давление. Далее идут бессмысленные запросы изменений.
Если есть два способа сделать что-то, потребуйте, чтобы код был изменён, чтобы сделать по-вашему. Не слушайте доказательств о недостатках вашего варианта. Включитесь в длинный спор почему это следует изменить.
Если не хватает аргументов заставьте соперника сомневаться в своих знаниях с помощью фраз вроде: «Я не знаю, почему вы так в штыки воспринимаете эту просьбу. Так, как я сказал, будет работать. Пожалуйста измените. Спасибо.»
Заставьте соперника потратить время на переписывание кода, который отлично работает.
3. Долгие задержки
Не торопитесь отвечать. Выждите как минимум 24 часа перед проверкой кода. Говорите, что заняты другими делами. Цель здесь состоит в том, чтобы сделать пулл-реквест (PR) устаревшим. Открытые PR считаются техническим долгом, потому что они требуют работы для поддержания. Это утомительная работа. Таким образом, вам нужно заставить PR провисеть как можно дольше, чтобы человеку приходилось тратить время на исправление конфликтов слияния.
Хороший способ сделать это — отказаться работать с PR, в котором есть конфликты слияния, потому что код может выглядеть по-другому после исправления, и вы не хотите тратить время на его просмотр, чтобы затем снова просматривать его после разрешения конфликтов. Это отличная тактика. Если сопернику не пришлось исправлять конфликты слияния хотя бы 2-3 раза, вы слишком быстро ему отвечаете!
4. Требуйте добавления багов
Просить о бесполезных изменениях — отличный способ добавить работы, но требовать внесения багов – это высший пилотаж! Ведь нужно поработать, чтобы добавить изменение, а затем соперник будет выглядеть глупо, когда ошибка обнаружится.
Проверяемый
1. Измените стиль кода в PR
Каждый PR, который вы отправляете на рассмотрение своему врагу, должен включать хотя бы 50% ненужных изменений стиля кода. Это сделает поиск фактических функциональных изменений настолько трудным, что он просто не глядя примет все ваши изменения.
2. Создавайте огромные PR
Ваша задача - заставить людей бояться обозревать ваш код. Это значит, что все PR должны содержать от 1000 изменений в как минимум 10 файлах.
Требуйте быстрого ответа. Это технический долг, и вы не хотите самостоятельно устранять конфликты слияния. Так что изводите всех, пока ваш PR не будет принят.
3. Игнорируйте комментарии
Отличный способ избежать негативных отзывов во время проверки кода — просто игнорировать их. Получили негативный комментарий? Попросите приятеля одобрить PR и слить его, не разбираясь с этим комментарием.
Итого
Если эти шаги повторять неоднократно и последовательно в течение нескольких месяцев, ваш враг пожалеет о том, что связался с вами!
Источник: https://repohealth.io/blog/code-review-how-to-make-enemies/
Обзор Кода: Как Нажить Себе Врагов
Иногда люди на работе раздражают вас, и вы чувствуете, что нужно отыграться. Если вы разрабатываете ПО, то способ есть – обзор кода! Это фантастический способ отомстить с помощью пассивно-агрессивных действий.
Проверяющий
1. Комментарии о стиле кода
У большинства компаний есть рекомендации по стилю кода. Изучите их! А затем начните просить об изменениях, которые явно не упомянуты. Если в рекомендациях по стилю кода что-то не упоминается, то это отличный шанс попросить внести бессмысленные изменения, которые просто заставят вашу жертву поработать:
- Правильно ли названы методы в классе модульного теста?
- Не слишком ли многословно названа переменная?
- Не используется синтаксис Йоды? Попросите изменить условия на противоположные.
2. Попросите об изменениях, которые не имеют смысла
Шаг 1 раздражает, но сам по себе он не смертелен. Нужно продолжать давление. Далее идут бессмысленные запросы изменений.
Если есть два способа сделать что-то, потребуйте, чтобы код был изменён, чтобы сделать по-вашему. Не слушайте доказательств о недостатках вашего варианта. Включитесь в длинный спор почему это следует изменить.
Если не хватает аргументов заставьте соперника сомневаться в своих знаниях с помощью фраз вроде: «Я не знаю, почему вы так в штыки воспринимаете эту просьбу. Так, как я сказал, будет работать. Пожалуйста измените. Спасибо.»
Заставьте соперника потратить время на переписывание кода, который отлично работает.
3. Долгие задержки
Не торопитесь отвечать. Выждите как минимум 24 часа перед проверкой кода. Говорите, что заняты другими делами. Цель здесь состоит в том, чтобы сделать пулл-реквест (PR) устаревшим. Открытые PR считаются техническим долгом, потому что они требуют работы для поддержания. Это утомительная работа. Таким образом, вам нужно заставить PR провисеть как можно дольше, чтобы человеку приходилось тратить время на исправление конфликтов слияния.
Хороший способ сделать это — отказаться работать с PR, в котором есть конфликты слияния, потому что код может выглядеть по-другому после исправления, и вы не хотите тратить время на его просмотр, чтобы затем снова просматривать его после разрешения конфликтов. Это отличная тактика. Если сопернику не пришлось исправлять конфликты слияния хотя бы 2-3 раза, вы слишком быстро ему отвечаете!
4. Требуйте добавления багов
Просить о бесполезных изменениях — отличный способ добавить работы, но требовать внесения багов – это высший пилотаж! Ведь нужно поработать, чтобы добавить изменение, а затем соперник будет выглядеть глупо, когда ошибка обнаружится.
Проверяемый
1. Измените стиль кода в PR
Каждый PR, который вы отправляете на рассмотрение своему врагу, должен включать хотя бы 50% ненужных изменений стиля кода. Это сделает поиск фактических функциональных изменений настолько трудным, что он просто не глядя примет все ваши изменения.
2. Создавайте огромные PR
Ваша задача - заставить людей бояться обозревать ваш код. Это значит, что все PR должны содержать от 1000 изменений в как минимум 10 файлах.
Требуйте быстрого ответа. Это технический долг, и вы не хотите самостоятельно устранять конфликты слияния. Так что изводите всех, пока ваш PR не будет принят.
3. Игнорируйте комментарии
Отличный способ избежать негативных отзывов во время проверки кода — просто игнорировать их. Получили негативный комментарий? Попросите приятеля одобрить PR и слить его, не разбираясь с этим комментарием.
Итого
Если эти шаги повторять неоднократно и последовательно в течение нескольких месяцев, ваш враг пожалеет о том, что связался с вами!
Источник: https://repohealth.io/blog/code-review-how-to-make-enemies/
👍12
Hanselminutes #852 - Mark Techson
Scott Hanselman
День 1298. #Подкаст #Карьера
Сегодня предлагаю послушать эпизод подкаста Скотта Хансельмана Hanselminutes: Mark Thompson wants you to win.
Марк Томпсон, старший инженер по связям с разработчиками в Google, хочет, чтобы вы выиграли. Они со Скоттом поговорили том, почему «дефицит мест» это неправильный способ думать о карьере в сфере технологий. Ваш успех не означает неудачи кого-то другого, и наоборот. Аналогично, передача знаний вашим ученикам или младшим коллегам (помимо того, что приносит удовлетворение) не означает, что они однажды займут ваше место. Места хватит всем.
Также Марк и Скотт обсудили вариацию синдрома самозванца при взгляде на более успешных коллег. Некоторые люди генетически предрасположены добиваться успеха в определённых сферах. Но то, что существует Леброн Джеймс вовсе не означает, что остальным 600 игрокам нечего делать в НБА. Выиграть могут все. Точно проиграет лишь тот, кто не будет участвовать.
Эти и другие советы относительно карьеры в новой серии подкаста.
Источник
Сегодня предлагаю послушать эпизод подкаста Скотта Хансельмана Hanselminutes: Mark Thompson wants you to win.
Марк Томпсон, старший инженер по связям с разработчиками в Google, хочет, чтобы вы выиграли. Они со Скоттом поговорили том, почему «дефицит мест» это неправильный способ думать о карьере в сфере технологий. Ваш успех не означает неудачи кого-то другого, и наоборот. Аналогично, передача знаний вашим ученикам или младшим коллегам (помимо того, что приносит удовлетворение) не означает, что они однажды займут ваше место. Места хватит всем.
Также Марк и Скотт обсудили вариацию синдрома самозванца при взгляде на более успешных коллег. Некоторые люди генетически предрасположены добиваться успеха в определённых сферах. Но то, что существует Леброн Джеймс вовсе не означает, что остальным 600 игрокам нечего делать в НБА. Выиграть могут все. Точно проиграет лишь тот, кто не будет участвовать.
Эти и другие советы относительно карьеры в новой серии подкаста.
Источник
👍4
День 1300. #ЧтоНовенького
Транзитивные Зависимости в Visual Studio
Чтобы помочь отслеживать транзитивные зависимости и быстро устранять уязвимости в Visual Studio 17.3 добавлена экспериментальная функция, которая поможет вам просматривать и принимать меры в отношении транзитивных зависимостей.
Теперь в окне управления NuGet пакетами есть новый раздел зависимостей, помеченный как «транзитивные пакеты», который вы можете при желании свернуть или развернуть. Вы можете нажимать на зависимости так же, как и на зависимости верхнего уровня, и даже повышать любую транзитивную зависимость до зависимости верхнего уровня. Одной из таких причин может быть устранение уязвимости в транзитивной зависимости, которое ещё не было исправлено в пакете верхнего уровня.
Наконец, вы можете навести указатель мыши на любую транзитивную зависимость, чтобы понять зависимости верхнего уровня, которые привели её в ваш проект.
Управление зависимостями для проекта — важная задача, требующая большей тщательности, чем когда-либо, чтобы правильно отслеживать множество библиотек, от которых вы можете зависеть.
Подробнее о том, как важно отслеживать зависимости в вашем проекте см. Рекомендации по Обеспечению Безопасности Проектов на GitHub
Источник: https://devblogs.microsoft.com/nuget/introducing-transitive-dependencies-in-visual-studio/
Транзитивные Зависимости в Visual Studio
Чтобы помочь отслеживать транзитивные зависимости и быстро устранять уязвимости в Visual Studio 17.3 добавлена экспериментальная функция, которая поможет вам просматривать и принимать меры в отношении транзитивных зависимостей.
Теперь в окне управления NuGet пакетами есть новый раздел зависимостей, помеченный как «транзитивные пакеты», который вы можете при желании свернуть или развернуть. Вы можете нажимать на зависимости так же, как и на зависимости верхнего уровня, и даже повышать любую транзитивную зависимость до зависимости верхнего уровня. Одной из таких причин может быть устранение уязвимости в транзитивной зависимости, которое ещё не было исправлено в пакете верхнего уровня.
Наконец, вы можете навести указатель мыши на любую транзитивную зависимость, чтобы понять зависимости верхнего уровня, которые привели её в ваш проект.
Управление зависимостями для проекта — важная задача, требующая большей тщательности, чем когда-либо, чтобы правильно отслеживать множество библиотек, от которых вы можете зависеть.
Подробнее о том, как важно отслеживать зависимости в вашем проекте см. Рекомендации по Обеспечению Безопасности Проектов на GitHub
Источник: https://devblogs.microsoft.com/nuget/introducing-transitive-dependencies-in-visual-studio/
👍4
День 1301. #ЗаметкиНаПолях #AsyncTips
Внедрение Запросов на Отмену
Задача: В коде присутствует уровень, который должен реагировать на запросы на отмену, а также выдавать собственные запросы на отмену на следующий уровень.
Решение
В системе отмены .NET предусмотрена встроенная поддержка этого сценария в виде связанных токенов отмены. Источник токена отмены может быть создан связанным с одним (или несколькими) существующими токенами. Когда вы создаёте источник связанного токена отмены, полученный токен будет отменяться при отмене любых из существующих токенов или при явной отмене связанного источника.
Следующий пример выполняет асинхронный запрос HTTP. Токен, переданный методу
Хотя в предыдущем примере используется только один источник
Помните о сроке существования источника связанного токена отмены. Предыдущий пример является наиболее типичным: один или несколько токенов отмены передаются методу, который связывает их и передает как комбинированный токен. Также обратите внимание на то, что в примере используется команда
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
Внедрение Запросов на Отмену
Задача: В коде присутствует уровень, который должен реагировать на запросы на отмену, а также выдавать собственные запросы на отмену на следующий уровень.
Решение
В системе отмены .NET предусмотрена встроенная поддержка этого сценария в виде связанных токенов отмены. Источник токена отмены может быть создан связанным с одним (или несколькими) существующими токенами. Когда вы создаёте источник связанного токена отмены, полученный токен будет отменяться при отмене любых из существующих токенов или при явной отмене связанного источника.
Следующий пример выполняет асинхронный запрос HTTP. Токен, переданный методу
GetWithTimeoutAsync
, представляет отмену, запрошенную конечным пользователем, а метод GetWithTimeoutAsync
также применяет тайм-аут к запросу:async Task<HttpResponseMessage>Полученный токен
GetWithTimeoutAsync(
HttpClient client,
string url,
CancellationToken ct)
{
using var cts = CancellationTokenSource
.CreateLinkedTokenSource(ct);
cts.CancelAfter(TimeSpan.FromSeconds(2));
var combined = cts.Token;
return await client.GetAsync(url, combined);
}
combined
отменяется либо когда пользователь отменяет существующий маркер ct
, либо при отмене связанного источника вызовом CancelAfter
.Хотя в предыдущем примере используется только один источник
CancellationToken
, метод CreateLinkedTokenSource
может получать любое количество токенов отмены в своих параметрах. Это позволяет создавать один объединённый токен, на базе которого можно реализовать собственную логическую отмену. Например, ASP.NET предоставляет токен отмены, представляющий отключение пользователя (HttpContext.RequestAborted); код обработчика может создать связанный токен, который реагирует либо на отключение пользователя, либо на свои причины отмены (например, тайм-аут).Помните о сроке существования источника связанного токена отмены. Предыдущий пример является наиболее типичным: один или несколько токенов отмены передаются методу, который связывает их и передает как комбинированный токен. Также обратите внимание на то, что в примере используется команда
using
, которая гарантирует, что источник связанного токена отмены будет освобожден, когда операция будет завершена (а комбинированный токен перестанет использоваться). Подумайте, что произойдет, если код не освободит источник связанного токена отмены: может оказаться, что метод GetWithTimeoutAsync
будет вызван несколько раз с одним (долгосрочным) существующим токеном; в этом случае код будет связывать новый источник токена при каждом вызове метода. Даже после того, как запросы HTTP завершатся (и ничто не будет использовать комбинированный токен), этот связанный источник всё ещё останется присоединённым к существующему токену. Чтобы предотвратить подобные утечки памяти, освобождайте источник связанного токена отмены, когда комбинированный токен перестаёт быть нужным.Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 10.
👍8