Как использовать enum в C#: объявление, значения и лучшие практики
Разбор использования перечислений в C# с нуля: объявление, задание значений, приведение типов, сравнение, перебор и практики, которые стоит применять в продакшене.
Читать статью здесь: https://bgh.st/djmghy
👉 @KodBlog
Разбор использования перечислений в C# с нуля: объявление, задание значений, приведение типов, сравнение, перебор и практики, которые стоит применять в продакшене.
Читать статью здесь: https://bgh.st/djmghy
Please open Telegram to view this post
VIEW IN TELEGRAM
Dev Leader
How to Use Enum in C#: Declaration, Values, and Best Practices
Learn how to use enum in C# from scratch. Covers declaring enums, assigning values, casting, comparing, iterating, and the best practices every C# developer sho
👍6🍾1
required string и string? в EF Core — это не просто разница в синтаксисе, это семантика модели и контракт с базой.
- required string → обязательная инициализация в модели + колонка NOT NULL в БД
- string? → допускает null + колонка с NULL в БД
EF Core использует nullable-аннотации и контекст компилятора, чтобы выводить ограничение целостности схемы. Это напрямую влияет на миграции и поведение трекинга изменений.
Важно: доменную модель нужно задавать явно, а бизнес-ограничения дублировать через Fluent API, чтобы исключить расхождения между кодом и схемой базы.
👉 @KodBlog
- required string → обязательная инициализация в модели + колонка NOT NULL в БД
- string? → допускает null + колонка с NULL в БД
EF Core использует nullable-аннотации и контекст компилятора, чтобы выводить ограничение целостности схемы. Это напрямую влияет на миграции и поведение трекинга изменений.
Важно: доменную модель нужно задавать явно, а бизнес-ограничения дублировать через Fluent API, чтобы исключить расхождения между кодом и схемой базы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🍾3
Node.js аддоны… на C#? Да.
Native AOT позволяет собирать нативные shared-библиотеки, которые подключаются напрямую через N-API — без node-gyp, без установки Python, без C++-обвязок.
Получается чистая межъязыковая связка через:
* UnmanagedCallersOnly
* LibraryImport
* Span<T>
* zero-alloc UTF-8 маршалинг
Идея — минимальный оверхед между Node.js и нативным кодом при сохранении управляемого кода на C#.
Блог: https://ift.tt/2mz8B1E
👉 @KodBlog
Native AOT позволяет собирать нативные shared-библиотеки, которые подключаются напрямую через N-API — без node-gyp, без установки Python, без C++-обвязок.
Получается чистая межъязыковая связка через:
* UnmanagedCallersOnly
* LibraryImport
* Span<T>
* zero-alloc UTF-8 маршалинг
Идея — минимальный оверхед между Node.js и нативным кодом при сохранении управляемого кода на C#.
Блог: https://ift.tt/2mz8B1E
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🍾2
Идемпотентность — одна из тех вещей, о которых не думаешь, пока один и тот же запрос не выполняется дважды.
Запрос может упасть, превысить таймаут или быть повторён клиентом. С точки зрения клиента это выглядит нормально. На стороне сервера в этот момент одно и то же действие может выполниться повторно. Если речь про создание заказа или проведение платежа, повторное выполнение приводит к неконсистентному состоянию.
Для этого используется идемпотентность.
Операция считается идемпотентной, если многократное выполнение даёт тот же результат, что и однократное. При одном или нескольких одинаковых запросах итоговое состояние системы не должно меняться.
Один из стандартных способов реализации — идемпотентный ключ. Клиент отправляет уникальный ключ вместе с запросом. Сервер сохраняет этот ключ и результат выполнения. При первом запросе он обрабатывает логику. При повторном запросе с тем же ключом обработка не запускается заново, возвращается сохранённый результат.
Это важно из-за повторов запросов, которые возникают регулярно. Сеть нестабильна, сервисы отвечают с задержками, клиенты автоматически делают ретраи.
Повторы останавливать не нужно. Нужно исключить повторное выполнение одной и той же операции.
👉 @KodBlog
Запрос может упасть, превысить таймаут или быть повторён клиентом. С точки зрения клиента это выглядит нормально. На стороне сервера в этот момент одно и то же действие может выполниться повторно. Если речь про создание заказа или проведение платежа, повторное выполнение приводит к неконсистентному состоянию.
Для этого используется идемпотентность.
Операция считается идемпотентной, если многократное выполнение даёт тот же результат, что и однократное. При одном или нескольких одинаковых запросах итоговое состояние системы не должно меняться.
Один из стандартных способов реализации — идемпотентный ключ. Клиент отправляет уникальный ключ вместе с запросом. Сервер сохраняет этот ключ и результат выполнения. При первом запросе он обрабатывает логику. При повторном запросе с тем же ключом обработка не запускается заново, возвращается сохранённый результат.
Это важно из-за повторов запросов, которые возникают регулярно. Сеть нестабильна, сервисы отвечают с задержками, клиенты автоматически делают ретраи.
Повторы останавливать не нужно. Нужно исключить повторное выполнение одной и той же операции.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤2🍾2
Глоббинг в C#
Несколько дней назад я сделал резервную копию документов в OneDrive и не заметил, что после завершения все файлы фактически были перенесены туда.
Далее я откатил резервную копию (20 ГБ), и во многих случаях процесс создал дубликаты.
Знание глоббинга позволило написать код для удаления дубликатов (5000+ файлов) и обхода отдельных папок.
Рекомендую уделить время изучению глоббинга.
Код: https://github.com/karenpayneoregon/learning-topics/tree/master/GlobbingApp1
👉 @KodBlog
Несколько дней назад я сделал резервную копию документов в OneDrive и не заметил, что после завершения все файлы фактически были перенесены туда.
Далее я откатил резервную копию (20 ГБ), и во многих случаях процесс создал дубликаты.
Знание глоббинга позволило написать код для удаления дубликатов (5000+ файлов) и обхода отдельных папок.
Рекомендую уделить время изучению глоббинга.
Код: https://github.com/karenpayneoregon/learning-topics/tree/master/GlobbingApp1
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔3❤1👍1🍾1
CQS и CQRS — это одно и то же?
Не совсем.
CQS (разделение команд и запросов) — это принцип:
команды изменяют состояние, ничего не возвращают
запросы возвращают данные, не изменяют состояние
он применяется на уровне методов и относится к намерению, а не к жёстким правилам.
CQRS строится на этой идее уже на архитектурном уровне. Он разделяет модели чтения и записи ради масштабируемости, ясности и гибкости.
Хочешь посмотреть, как реализовать CQRS на практике?
Вот как: читать
Большинство приложений уже делают это, даже без прямого упоминания CQRS.
👉 @KodBlog
Не совсем.
CQS (разделение команд и запросов) — это принцип:
команды изменяют состояние, ничего не возвращают
запросы возвращают данные, не изменяют состояние
он применяется на уровне методов и относится к намерению, а не к жёстким правилам.
CQRS строится на этой идее уже на архитектурном уровне. Он разделяет модели чтения и записи ради масштабируемости, ясности и гибкости.
Хочешь посмотреть, как реализовать CQRS на практике?
Вот как: читать
Большинство приложений уже делают это, даже без прямого упоминания CQRS.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🍾2
azure-alphabet.pdf
2.5 MB
Хочешь уверенно работать с Azure как бэкенд-разработчик на .NET?
Кристи потратил 20+ часов, чтобы собрать «Алфавит Azure для тебя:
• Разобраться в 26 ключевых сервисах и концепциях Azure (без воды)
• Понимать, что делает каждый сервис, когда его использовать и зачем он нужен
• Стартовать путь разработки в Azure
Я его скачал и делюсь с вами!❤️ ❤️
👉 @KodBlog
Кристи потратил 20+ часов, чтобы собрать «Алфавит Azure для тебя:
• Разобраться в 26 ключевых сервисах и концепциях Azure (без воды)
• Понимать, что делает каждый сервис, когда его использовать и зачем он нужен
• Стартовать путь разработки в Azure
Я его скачал и делюсь с вами!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🍾1
Самый простой способ генерировать PDF-отчёты
Первый выбор — конвертация HTML → PDF.
В большинстве коммерческих проектов используется IronPDF.
Нужен бесплатный вариант:
- Puppeteer Sharp
- headless-версия Chrome
Но ключевая идея важнее конкретного инструмента.
Если есть HTML-шаблон, появляется полный контроль над форматированием.
Можно использовать современный CSS для стилизации HTML-разметки.
Общая схема реализации:
1. MVC-представления и Razor-синтаксис
2. Рендер динамического HTML-контента
3. Передача HTML в PDF-рендерер
Такой подход использовался в нескольких проектах с хорошими результатами.
Нужен пример реализации гибкой PDF-генерации?
Гайд: тут
👉 @KodBlog
Первый выбор — конвертация HTML → PDF.
В большинстве коммерческих проектов используется IronPDF.
Нужен бесплатный вариант:
- Puppeteer Sharp
- headless-версия Chrome
Но ключевая идея важнее конкретного инструмента.
Если есть HTML-шаблон, появляется полный контроль над форматированием.
Можно использовать современный CSS для стилизации HTML-разметки.
Общая схема реализации:
1. MVC-представления и Razor-синтаксис
2. Рендер динамического HTML-контента
3. Передача HTML в PDF-рендерер
Такой подход использовался в нескольких проектах с хорошими результатами.
Нужен пример реализации гибкой PDF-генерации?
Гайд: тут
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🍾1
Совет по LINQ:
Вызывай
Почему?
> В первом случае всё загружается в память до фильтрации
> Во втором — фильтрация происходит на источнике, что лучше для БД или больших коллекций
> Особенно важно при работе с EF Core или API, использующих
🎉 🎉
👉 @KodBlog
Вызывай
ToList() после фильтрации, а не до.Почему?
> В первом случае всё загружается в память до фильтрации
> Во втором — фильтрация происходит на источнике, что лучше для БД или больших коллекций
> Особенно важно при работе с EF Core или API, использующих
IQueryablePlease open Telegram to view this post
VIEW IN TELEGRAM
🥴12😁6🤯3🍾1
Что такое Queue<T>?
Queue<T> — это коллекция в C# с принципом FIFO (первым пришёл — первым ушёл).
То есть первый добавленный элемент будет извлечён первым.
Когда использовать?
> Планирование задач
> Очереди на печать
> Обработка сообщений
> Поиск в ширину (BFS) в графах
Пример прикрепил, с вас лайк❤️
👉 @KodBlog
Queue<T> — это коллекция в C# с принципом FIFO (первым пришёл — первым ушёл).
То есть первый добавленный элемент будет извлечён первым.
Когда использовать?
> Планирование задач
> Очереди на печать
> Обработка сообщений
> Поиск в ширину (BFS) в графах
Пример прикрепил, с вас лайк
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤1🍾1💋1
Ubuntu 26.04 поставляется с .NET 10 из коробки: новые контейнерные образы -resolute, готовность к Linux 7.0, постквантовая криптография и чистая поддержка cgroup v2.
Native AOT работает быстро: компактные бинарники + ~3 мс запуска. .NET 8/9 доступны через PPA с бэкпортами.
👉 @KodBlog
Native AOT работает быстро: компактные бинарники + ~3 мс запуска. .NET 8/9 доступны через PPA с бэкпортами.
Please open Telegram to view this post
VIEW IN TELEGRAM
Microsoft News
What’s new for .NET in Ubuntu 26.04
Ubuntu 26.04 (Resolute Raccoon) ships today with .NET 10. Here's how to install .NET 10 from the archive, use the new -resolute container tags, build Native AOT apps, and install .NET 8 and 9 from the dotnet-backports PPA.
👍10🔥5🍾4
EF Core имеет заметную просадку производительности при использовании колонок-идентификаторов.
Как это обычно решают ?
В большинстве проектов для первичных ключей используют либо автоинкремент из базы данных, либо GUID.
При вызове метода SaveChanges EF Core возвращает сгенерированное значение идентификатора, которое сформировала база.
В SQL Server EF Core применяет оператор MERGE с предложением OUTPUT, чтобы объединять множественные вставки в один запрос и возвращать новые значения идентификаторов.
Подход рабочий, но у него есть жёсткие ограничения:
- лимит в 2100 параметров: SQL Server допускает максимум 2100 параметров на один запрос. При 14 колонках это примерно 100–200 строк за одну партию. Для 10 000 строк Product это приводит к множеству обходных вызовов к базе.
- стоимость привязки параметров: каждый параметр создаётся, привязывается и отправляется по сети. Для больших объёмов это десятки тысяч параметров.
- нагрузка на отслеживание изменений: после каждой партии EF Core обновляет трекер изменений и присваивает возвращённые идентификаторы объектам.
Это заметно ухудшает производительность при массовых вставках.
При этом часто нет необходимости возвращать идентификаторы сразу после вставки.
Заявленный результат:
10 000 записей Product.
EF Core SaveChanges с возвратом идентификаторов: ~7000 мс.
Оптимизированная вставка: ~200 мс.
👉 @KodBlog
Как это обычно решают ?
В большинстве проектов для первичных ключей используют либо автоинкремент из базы данных, либо GUID.
При вызове метода SaveChanges EF Core возвращает сгенерированное значение идентификатора, которое сформировала база.
В SQL Server EF Core применяет оператор MERGE с предложением OUTPUT, чтобы объединять множественные вставки в один запрос и возвращать новые значения идентификаторов.
Подход рабочий, но у него есть жёсткие ограничения:
- лимит в 2100 параметров: SQL Server допускает максимум 2100 параметров на один запрос. При 14 колонках это примерно 100–200 строк за одну партию. Для 10 000 строк Product это приводит к множеству обходных вызовов к базе.
- стоимость привязки параметров: каждый параметр создаётся, привязывается и отправляется по сети. Для больших объёмов это десятки тысяч параметров.
- нагрузка на отслеживание изменений: после каждой партии EF Core обновляет трекер изменений и присваивает возвращённые идентификаторы объектам.
Это заметно ухудшает производительность при массовых вставках.
При этом часто нет необходимости возвращать идентификаторы сразу после вставки.
Заявленный результат:
10 000 записей Product.
EF Core SaveChanges с возвратом идентификаторов: ~7000 мс.
Оптимизированная вставка: ~200 мс.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤3🍾1
Использование нативной компиляции AOT в .NET для сборки DLL под Windows WinAPI: читать
Я пропустил один момент с AOT: через него можно собирать нативные библиотеки динамической компоновки. Проверил на практике — получаются небольшие стандартные DLL в стиле WinAPI, которые можно вызывать из легаси-приложений.
👉 @KodBlog
Я пропустил один момент с AOT: через него можно собирать нативные библиотеки динамической компоновки. Проверил на практике — получаются небольшие стандартные DLL в стиле WinAPI, которые можно вызывать из легаси-приложений.
Please open Telegram to view this post
VIEW IN TELEGRAM
West-Wind
Using .NET Native AOT to build Windows WinAPI Dlls
Did you know that you can use .NET AOT compilation to create native Windows DLLs to potentially replace traditional C/C++ compiled DLLs? It's now possible to build completely native DLLs that can be called from external applications and legacy applications…
👍5🍾2
.NET MAUI работает на Linux через GTK4. Команда экспериментирует с этим в maui-labs, и реализация уже выглядит очень полной. Есть Shell, Blazor Hybrid, CollectionView, жесты, анимации. Всё на нативных виджетах GTK4.
https://github.com/dotnet/maui-labs/tree/main/platforms/Linux.Gtk4
👉 @KodBlog
https://github.com/dotnet/maui-labs/tree/main/platforms/Linux.Gtk4
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15🍾5
SkiaSharp 4.0 Preview 1 вышел — более быстрый рендеринг, более чистые API и более умное формирование текста для .NET-приложений, которые рисуют… что угодно.
Попробуй и посмотри, на что теперь способны твои графические компоненты: https://ift.tt/k9wTbRv
👉 @KodBlog
Попробуй и посмотри, на что теперь способны твои графические компоненты: https://ift.tt/k9wTbRv
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🍾2
Я написал два почти одинаковых SQL-запроса.
Один из них оказался быстрее в 451 раз.
Я реализовывал постраничную навигацию через курсор.
И подумал: почему бы не добавить индекс, чтобы ускорить запрос?
Вот здесь всё пошло не по плану.
Есть сканирование индекса через составной индекс. На первый взгляд — всё нормально.
Но запрос стал даже медленнее, чем без индекса.
В чём причина?
Можно было бы подумать, что дело в слишком маленьком объёме данных, где индекс просто не даёт выгоды.
Но дело было не в этом…
А что если использовать сравнение кортежей в SQL?
В итоге индекс начал работать — 0.668 мс.
Оптимизатор запросов не смог корректно понять, можно ли применить составной индекс для построчного сравнения.
Но при сравнении кортежей индекс начал использоваться эффективно.
Если бы я не посмотрел план выполнения запроса, я бы это не понял.
👉 @KodBlog
Один из них оказался быстрее в 451 раз.
Я реализовывал постраничную навигацию через курсор.
И подумал: почему бы не добавить индекс, чтобы ускорить запрос?
Вот здесь всё пошло не по плану.
Есть сканирование индекса через составной индекс. На первый взгляд — всё нормально.
Но запрос стал даже медленнее, чем без индекса.
В чём причина?
Можно было бы подумать, что дело в слишком маленьком объёме данных, где индекс просто не даёт выгоды.
Но дело было не в этом…
А что если использовать сравнение кортежей в SQL?
В итоге индекс начал работать — 0.668 мс.
Оптимизатор запросов не смог корректно понять, можно ли применить составной индекс для построчного сравнения.
Но при сравнении кортежей индекс начал использоваться эффективно.
Если бы я не посмотрел план выполнения запроса, я бы это не понял.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2🍾2
Стоит ли перестать использовать случайные UUID в .NET?
Классический UUID через
Из-за случайного порядка появляются:
- дорогие ребалансировки индексов;
- просадка скорости вставки;
- высокая фрагментация.
Поэтому многие перешли на ULID — 128-битный сортируемый идентификатор с сохранением уникальности.
ULID сохраняет временной порядок генерации, благодаря чему лучше работает с индексами.
Но начиная с .NET 9 появился более нативный вариант:
✅
UUID V7 — это time-ordered UUID с полной совместимостью с
Фактически получаете преимущества ULID, но уже встроенные в .NET.
👉 @KodBlog
Классический UUID через
Guid.NewGuid() генерируется случайным образом. Для уникальности это отлично, но для базы данных — не лучший вариант.Из-за случайного порядка появляются:
- дорогие ребалансировки индексов;
- просадка скорости вставки;
- высокая фрагментация.
Поэтому многие перешли на ULID — 128-битный сортируемый идентификатор с сохранением уникальности.
ULID сохраняет временной порядок генерации, благодаря чему лучше работает с индексами.
Но начиная с .NET 9 появился более нативный вариант:
Guid.CreateVersion7()UUID V7 — это time-ordered UUID с полной совместимостью с
Guid, без сторонних пакетов.Фактически получаете преимущества ULID, но уже встроенные в .NET.
Please open Telegram to view this post
VIEW IN TELEGRAM
👌8🔥3🍾1
This media is not supported in your browser
VIEW IN TELEGRAM
Каждый бэкенд-инженер должен уметь ответить на вопрос:
Что произойдёт, если база данных упадёт посреди транзакции?
Причины могут быть разные: отключение питания, сбой оборудования и т.д.
Чтобы не потерять данные, система должна сохранять их на энергозависимом хранилище, например, на диске.
Когда пользователь выполняет транзакцию, база данных делает две вещи:
> записывает данные в отдельный лог
> применяет обновление
Лог нужен для повторной обработки транзакции при перезапуске, чтобы восстановить консистентное состояние после сбоя.
Запись в лог быстрая, так как это бинарный файл с добавлением только в конец (append-only).
Это исключает затратные операции поиска по файлу.
А если база распределённая?
Тут сложнее — серверам базы нужно координироваться с помощью протокола двухфазной фиксации (2PC).
В этом процессе один из серверов выступает координатором:
> он отправляет всем участникам запрос на коммит
> ждёт подтверждения от всех
> затем сообщает коммитить или откатить транзакцию
👉 @KodBlog
Что произойдёт, если база данных упадёт посреди транзакции?
Причины могут быть разные: отключение питания, сбой оборудования и т.д.
Чтобы не потерять данные, система должна сохранять их на энергозависимом хранилище, например, на диске.
Когда пользователь выполняет транзакцию, база данных делает две вещи:
> записывает данные в отдельный лог
> применяет обновление
Лог нужен для повторной обработки транзакции при перезапуске, чтобы восстановить консистентное состояние после сбоя.
Запись в лог быстрая, так как это бинарный файл с добавлением только в конец (append-only).
Это исключает затратные операции поиска по файлу.
А если база распределённая?
Тут сложнее — серверам базы нужно координироваться с помощью протокола двухфазной фиксации (2PC).
В этом процессе один из серверов выступает координатором:
> он отправляет всем участникам запрос на коммит
> ждёт подтверждения от всех
> затем сообщает коммитить или откатить транзакцию
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥3❤🔥2🍾1