csharp_ci | Unsorted

Telegram-канал csharp_ci - C# (C Sharp) programming

18377

По всем вопросам- @haarrp C# - обучающий канал Senior C# разработчика. @ai_machinelearning_big_data - Machine learning @itchannels_telegram - 🔥лучшие ит-каналы @csharp_ci - C# академия @pythonlbooks- книги📚 Реестр РКН: https://clck.ru/3Fk3kb

Subscribe to a channel

C# (C Sharp) programming

Fenwick Tree на C#: всё держится на одном битовом трюке

Fenwick Tree, или Binary Indexed Tree, считает prefix sums за O(log n).

Главная операция:


i & -i


Она находит младший установленный бит числа.

Именно это значение говорит структуре, на сколько нужно прыгнуть по индексам.

Пример:


i = 12 // 1100
i & -i = 4 // 0100


Реализация на C#:


public sealed class FenwickTree
{
private readonly int[] _tree;

public FenwickTree(int size)
{
_tree = new int[size + 1];
}

public void Update(int index, int delta)
{
while (index < _tree.Length)
{
_tree[index] += delta;
index += index & -index;
}
}

public int Query(int index)
{
var sum = 0;

while (index > 0)
{
sum += _tree[index];
index -= index & -index;
}

return sum;
}
}


Как это работает:

* Update идёт вверх по структуре и обновляет все узлы, которые отвечают за индекс
* Query идёт вниз и собирает блоки, из которых состоит prefix sum
* index & -index каждый раз выбирает размер текущего блока

Главный нюанс: Fenwick Tree обычно использует 1-based indexing.

То есть первый элемент имеет индекс 1, а не 0.

Пример использования:


var tree = new FenwickTree(5);

tree.Update(1, 10);
tree.Update(2, 20);
tree.Update(3, 30);

Console.WriteLine(tree.Query(3)); // 60


Красота Fenwick Tree в том, что дерево не хранится явно.

• Нет узлов.
• Нет ссылок.
• Нет рекурсии.

Только массив и один битовый трюк.

Дерево спрятано прямо внутри двоичного представления индексов.

Читать полностью…

C# (C Sharp) programming

Приходи на C# Speed Dating — 2 часа на полезные знакомства

23 июня пройдет вечер коротких онлайн-знакомств для C#-разработчиков.

Как все пройдет
Участники будут рандомно делиться по парам и общаться в Zoom. Будет 6 раундов по 10 минут.

Зачем приходить
— обсудишь темы, которые вызывают споры: AI, карьера, архитектурные паттерны и метрики.
— заберешь идеи и практики, которые работают у других, и поделишься своим опытом.
— найдешь полезные контакты и познакомишься с C#-коммьюнити.

Вечер организуют ребята из Mindbox, но они будут «без оружия»: никакого хантинга и рассказов про вакансии, пока ты сам не спросишь.

📅 23 июня
⏰ 19:00–21:00 по мск
📍 Zoom (пришлем ссылку после регистрации)

👉 Зарегистрироваться

Читать полностью…

C# (C Sharp) programming

⚡️ Переписывать legacy-систему редко значит «переписать код». Обычно самая дорогая часть начинается там, где старый и новый мир должны какое-то время жить одновременно.

Типичная проблема - синхронизация данных между старой БД и новой моделью. На бумаге кажется, что можно взять CDC, подключить Debezium, прокинуть события и жить спокойно. На практике это работает только пока у вас почти прямое соответствие: таблица → событие → таблица.

В реальном legacy всё еще хуже.

Одна запись в старой системе может собираться из нескольких агрегатов в новой. Поля могут иметь другой смысл. Часть данных нормализована, часть размазана по справочникам, часть хранится как «магические» статусы. А ещё при переносе нужно не просто скопировать байты, а применить бизнес-правила: пересчитать состояние, отфильтровать мусор, восстановить инварианты, иногда даже специально повторить старый баг, потому что на нём завязан внешний процесс.

Нормальное решение может выглядеть так:

* события из новой системы публикуются через outbox, а не напрямую из хендлера
* синхронизатор читает сообщения из RabbitMQ или другого брокера
* трансформации делаются явно, через application service или отдельный mapping layer
* операции проектируются идемпотентными, потому что повторная доставка будет всегда
* для каждой внешней записи хранится mapping старого и нового идентификатора
* ошибки не теряются, а уходят в retry/DLQ с понятной диагностикой
* консистентность проверяется отдельными reconciliation jobs, а не верой в «оно доедет»

Такой синхронизатор выглядит как временный костыль, но по сложности быстро становится полноценной подсистемой. У него появляются свои контракты, версии сообщений, миграции, алерты, метрики, ручные repair-команды и отдельные сценарии восстановления после падений.

Если всё сделано хорошо, этот компонент потом удалят. Он нужен только на период миграции. Но если сделать его плохо, миграция не закончится никогда.

Читать полностью…

C# (C Sharp) programming

🐳 «Используй Testcontainers вместо in-memory» - это только половина правды

Все уже выучили: EF Core InMemory provider - не интеграционный тест.

Он не ловит:

- баги в LINQ-трансляции
- ограничения БД
- коллации
- реальные типы колонок
- поведение конкретного SQL-провайдера

Окей, заменили на реальный PostgreSQL через Testcontainers. Победа? Не совсем.

Вот что начинается дальше.

1. Вы получили «медленное враньё» вместо «быстрого»

Поднимать контейнер на каждый тест-класс - быстрый способ превратить CI из 30 секунд в 8 минут.

Нормальный вариант:

- один контейнер на всю тестовую сессию
- изоляция данных между тестами через Respawn
- без пересоздания базы и контейнера каждый раз

Respawn чистит таблицы с учётом графа foreign keys за миллисекунды.

2. Транзакционный откат ≠ реальный сценарий

Трюк «обернули тест в транзакцию и откатили» красиво выглядит, но ломается, когда в коде есть:

- свои транзакции
- несколько SaveChanges
- фоновые операции
- поведение, завязанное на commit

В итоге тестируется сценарий, которого в проде нет.

3. Самая коварная ловушка - общий DbContext

Если тест и код используют один экземпляр DbContext, EF может вернуть данные из change tracker, а не из базы.

Тест зелёный, но он врёт: реальный SQL-запрос мог вообще не выполниться.

Между Act и Assert стоит чистить трекер:


Db.ChangeTracker.Clear();


4. Бонус, который теряют 90% команд - тест миграций

Реальная БД позволяет прогнать EF-миграции на чистой схеме.

Если миграция падает или схема разъехалась с моделью, вы узнаёте об этом в CI, а не в проде в пятницу вечером.

Пример базового подхода:


public class IntegrationTestBase : IAsyncLifetime
{
private static readonly PostgreSqlContainer _db =
new PostgreSqlBuilder()
.WithImage("postgres:16-alpine")
.Build();

private Respawner _respawner = null!;
protected AppDbContext Db = null!;

public async Task InitializeAsync()
{
await _db.StartAsync();

var options = new DbContextOptionsBuilder<AppDbContext>()
.UseNpgsql(_db.GetConnectionString())
.Options;

Db = new AppDbContext(options);

// Реальные миграции - заодно проверяем, что они накатываются
await Db.Database.MigrateAsync();

await using var conn = new NpgsqlConnection(_db.GetConnectionString());
await conn.OpenAsync();

_respawner = await Respawner.CreateAsync(conn, new RespawnerOptions
{
DbAdapter = DbAdapter.Postgres,
SchemasToInclude = ["public"]
});
}

// Сброс данных перед каждым тестом - без пересоздания контейнера
protected async Task ResetAsync()
{
await using var conn = new NpgsqlConnection(_db.GetConnectionString());
await conn.OpenAsync();

await _respawner.ResetAsync(conn);

// Иначе тест может читать из кеша, а не из БД
Db.ChangeTracker.Clear();
}

public Task DisposeAsync() => Task.CompletedTask;
}


Testcontainers - это не галочка «best practice», а смена философии.

Без нормальной изоляции данных вы просто пересели с быстрого вранья на медленное.

А как вы изолируете состояние БД между интеграционными тестами - Respawn, транзакции или пересоздание контейнера?

#dotnet #csharp #testing #efcore

Читать полностью…

C# (C Sharp) programming

✔️ Одна строчка .Result роняет ваш ASP.NET Core при CPU 8 %: разбор hill-climbing в .NET 9

TL;DR. Один foo.GetAsync().Result внутри middleware превращает ASP.NET Core, державший 50k RPS на p99 = 40 мс, в сервис на 12k RPS с p99 = 4 с при CPU 8 %. Виноват не блокирующий вызов сам по себе.

Виноват hill-climbing: фидбэк-луп в ThreadPool, внутри которого живёт дискретное преобразование Фурье.

Разбираемся по исходникам CoreCLR, как это работает, воспроизводим эффект на ~80 строках кода и показываем, почему SetMinThreads это не лечение, а анестезия.

https://habr.com/ru/articles/1040804/

Читать полностью…

C# (C Sharp) programming

🖥 Сервисы крутятся. Прод вроде живой. Но когда тимлид спрашивает: «почему здесь лучше ValueTask, а не Task?» или «как GC поведёт себя под нагрузкой?» - ты начинаешь плыть.

И дело не в том, что ты плохо пишешь код. Просто большинство курсов заканчиваются ровно там, где начинается настоящий .NET.

Этот курс про то, что обычно остаётся под капотом:

- CLR
- JIT
- GC
- Span
- async state machine
- Source Generators
- lock-free подходы
- OpenTelemetry
- дампы в проде

На практике разбираем, как .NET реально работает внутри: что происходит с кодом после компиляции, как память живёт под нагрузкой, почему async иногда помогает, а иногда ломает производительность, как читать проблемы по дампам и метрикам, а не гадать по логам.

Если хочешь дойти до уровня, где система для тебя не чёрный ящик, а инструмент, который ты понимаешь до IL, - велкам.

Сейчас на stepik доступна скидка 55%: https://stepik.org/a/288694

Читать полностью…

C# (C Sharp) programming

📌 OpenAI показала редкий для ИИ результат: внутренняя модель самостоятельно нашла контрпример к известной задаче из дискретной геометрии, которую Пал Эрдёш сформулировал ещё в 1946 году.

Суть задачи простая: есть n точек на плоскости. Нужно понять, сколько пар точек могут находиться ровно на расстоянии 1 друг от друга.

Долгое время считалось, что почти оптимальный ответ дают конструкции, похожие на квадратную решётку. Модель OpenAI показала, что это неверно.

Она построила бесконечное семейство конфигураций, где таких пар получается заметно больше, чем ожидалось. То есть была опровергнута не мелкая техническая деталь, а известная гипотеза, вокруг которой десятилетиями строились оценки.

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

В доказательстве используются решётки Минковского (способ превратить числа из алгебраической теории чисел в точки в обычном евклидовом пространстве), элементы нормы один и pro-3 башни числовых полей. Это инструменты из другой части математики, и именно их перенос в геометрию дал результат.

Нога Алон из Принстона отметил, что ответ оказался неожиданным, а применённые методы выглядят элегантно и нетривиально.

При этом доказательство не даёт нового «чисто геометрического» метода, на который многие надеялись. Гипотеза опровергнута, но сама структура задачи стала ещё интереснее.

Задачу сформулировал ИИ, решение сгенерировала внутренняя модель OpenAI, первичная проверка тоже прошла через автоматический ИИ-пайплайн. После этого люди проверили детали, улучшили изложение и довели работу до публикации.

Модель сама нашла неочевидную связь между разными областями математики и получила результат по открытой задаче высокого уровня.

Оригинал: https://openai.com/index/model-disproves-discrete-geometry-conjecture/

@ai_machinelearning_big_data

Читать полностью…

C# (C Sharp) programming

15 проезный .NET-библиотек, которые используют senior-разработчики

Open-source библиотеки, которые делают код чище, тесты надёжнее, а разработку быстрее.


**HTTP, устойчивость и DI**

**1. Refit**
Превращает REST API в типизированные C# интерфейсы. Меньше boilerplate вокруг HttpClient.
GitHub: https://github.com/reactiveui/refit

2. Polly
Retry, circuit breaker, timeout и resilience-политики для исходящих вызовов.
GitHub: https://github.com/App-vNext/Polly

3. Scrutor
Автосканирование и регистрация сервисов в DI по конвенциям.
GitHub: https://github.com/khellang/Scrutor

Тестирование

4. Bogus
Генератор реалистичных fake-данных для тестов и сидинга.
GitHub: https://github.com/bchavez/Bogus

5. Verify
Snapshot-тесты для .NET: один раз утвердил вывод, дальше ловишь регрессии.
GitHub: https://github.com/VerifyTests/Verify

6. Testcontainers for .NET
Поднимает реальный PostgreSQL, SQL Server, Redis и другие сервисы в Docker для интеграционных тестов.
GitHub: https://github.com/testcontainers/testcontainers-dotnet

API и фоновые задачи

7. FastEndpoints
Быстрые Minimal API по паттерну REPR без раздутых контроллеров.
Сайт: https://fast-endpoints.com
GitHub: https://github.com/FastEndpoints/FastEndpoints

8. TickerQ
Нативный планировщик фоновых задач без Hangfire, Quartz и лишнего оверхеда.
GitHub: https://github.com/Arcenox-co/TickerQ

9. HotChocolate
Мощный GraphQL-сервер для .NET, когда один гибкий endpoint удобнее десятков REST-маршрутов.
Сайт: https://chillicream.com/docs/hotchocolate
GitHub: https://github.com/ChilliCream/graphql-platform

Микросервисы и messaging

10. Dapr
Service discovery, pub/sub и state management для микросервисов без лишней инфраструктурной сантехники.
Сайт: https://dapr.io
GitHub: https://github.com/dapr/dotnet-sdk

11. Wolverine
Mediator и messaging в одном фреймворке. Как MediatR, только шире по возможностям.
Сайт: https://wolverinefx.net
GitHub: https://github.com/JasperFx/wolverine

Утилиты и работа с данными

12. UnitsNet
Безопасная работа с единицами измерения вместо сырых double для температуры, скорости и расстояний.
GitHub: https://github.com/angularsen/UnitsNet

13. Humanizer
Превращает строки, даты, числа и enum-ы в читаемый вид одной строкой кода.
GitHub: https://github.com/Humanizr/Humanizer

14. ImageSharp
Обработка, ресайз и конвертация изображений в .NET. Кросс-платформенно, без GDI+.
Сайт: https://sixlabors.com/products/imagesharp
GitHub: https://github.com/SixLabors/ImageSharp

Архитектура

15. ArchUnitNET
Тесты для архитектурных правил. Нарушения слоёв и Clean Architecture падают прямо в CI.
GitHub: https://github.com/TNG/ArchUnitNET

Читать полностью…

C# (C Sharp) programming

#ПятничныйКвиз #МыЗнаемТолкВИзвращениях

Читать полностью…

C# (C Sharp) programming

📌 UUID v7 - это почти ULID, только нативно в .NET

Раньше в .NET для идентификаторов чаще всего использовали обычный Guid.NewGuid().

Проблема в том, что классический UUID случайный. Для уникальности это удобно, но для базы данных - не всегда.

Когда значения генерируются хаотично, новые записи вставляются в разные части индекса. Отсюда:

- больше фрагментации
- дороже вставки
- чаще перестраиваются страницы индекса
- хуже поведение на больших таблицах

Поэтому многие разработчики начали использовать ULID.

ULID состоит из двух частей:

- timestamp
- random

За счет timestamp такие ID сортируются по времени, а значит база может вставлять новые записи более последовательно.

Но начиная с .NET 9 появился встроенный вариант:

Guid.CreateVersion7()

UUID v7 тоже содержит временную часть, поэтому лучше подходит для индексируемых ключей, чем полностью случайный UUID.

Главное отличие:

ULID - отдельный формат и часто сторонняя библиотека.
UUID v7 - обычный Guid, который уже поддерживается в .NET.

Для новых проектов это выглядит как более разумный дефолт:

- не Guid.NewGuid()
- не отдельный ULID-пакет
- а Guid.CreateVersion7()

Особенно если Guid используется как primary key в базе.

Читать полностью…

C# (C Sharp) programming

Одна функция в C однажды положила заметную часть раннего интернета.

В 1988 году в стандартной библиотеке C была функция `gets()`. Она читала ввод пользователя в буфер, но не проверяла его размер. Если данных приходило больше, чем помещалось, они просто начинали затирать соседнюю память.

Именно это использовал Robert Morris в знаменитом Morris Worm. Червь атаковал `fingerd`, переполнял буфер и заставлял систему выполнять чужой код.

Итог: около 6000 машин были заражены за считанные часы. По оценкам того времени, это была примерно десятая часть всего интернета.

Самое безумное здесь не сам червь, а то, насколько маленькой была причина. Один небезопасный вызов. Один буфер без проверки. Одна функция, которую годами использовали как обычный инструмент.

Позже `gets()` признали настолько опасной, что её фактически выкинули из современного C.

Урок простой: в системном программировании безопасность часто ломается не на сложной криптографии, а на банальном «а что будет, если ввод окажется длиннее, чем мы ожидали?»

#history

Читать полностью…

C# (C Sharp) programming

🖥 Курс «Git Pro: от первого коммита до уровня senior» - на Stepik

project_final_v2_FINAL_truly_final - знакомо?

Значит, пора.

Большинство разработчиков знают 5 команд Git и боятся шестую. Коммитят в main, гуглят «how to undo» и копируют папку «на всякий случай».

Это не работа - это выживание.

После курса вы:
— делаете rebase, не задерживая дыхание;
— разбираете конфликт на 200 файлов по алгоритму;
— возвращаете «потерянные навсегда» коммиты за 30 секунд через reflog;
— пишете историю, которую не стыдно показать на code review.
Git Flow, trunk-based, Pull Request, защита веток, CI/CD-хуки — всё, что отличает джуна от senior в командной работе.

Скидка 53%, 48 часов: https://stepik.org/course/284799/

Читать полностью…

C# (C Sharp) programming

В C# 15 появились union types. И это не косметика, это смена подхода к обработке ошибок.

Вы можете явно описать результат как “либо значение, либо ошибка”, прямо на уровне языка.

Без самодельных Result-классов, без лишних обёрток, без попыток использовать исключения там, где они неуместны.

Раньше, ты либо городишь свой Result и работаешь с лишним бойлерплейтом.
Либо тащишь сторонние библиотеки.

Либо кидаешь исключения и теряешь контроль над потоком.

С union types эта проблема решается .

Pattern matching начинает работать так, как и должен. Ты не гадаешь, что вернул метод, а явно разбираешь все варианты.

Код становится проще читать, проще тестировать и сложнее сломать.

Читать полностью…

C# (C Sharp) programming

⚡️ Версионирование API в Minimal APIs без лишней магии

Если вы пишете API на ASP.NET Core и планируете жить с ним дольше одного релиза, версионирование лучше заложить сразу.

Minimal APIs отлично дружат с ApiVersionSet: можно явно объявить поддерживаемые версии, включить репортинг доступных версий и привязать конкретный endpoint к нужной версии.

В примере создается набор версий API:

v1 - текущая стабильная версия
v2 - новая версия для развития контракта

После этого endpoint /api/v{version:apiVersion}/workouts/{workoutId} получает привязку через .WithApiVersionSet(apiVersionSet) и явно мапится на .MapToApiVersion(1).

Главная идея простая: версия становится частью маршрута, а не скрытой договоренностью между клиентом и backend.

Это особенно важно, когда API уже используют мобильные приложения, внешние интеграции или несколько фронтендов. Вы можете развивать v2, не ломая клиентов, которые все еще сидят на v1.

Для C# backend-разработчика это один из тех паттернов, который выглядит мелочью на старте, но сильно экономит нервы на проде.

Читать полностью…

C# (C Sharp) programming

🖥 На Stepik обновили курс «C# с нуля до профи»

Представьте: через четыре месяца вы открываете чужой .NET-проект и читаете его как книгу.

IServiceCollection не вызывает ступора. async Task<IActionResult> пишется на автомате. Вы точно знаете, почему EF Core сгенерировал именно такой SQL - и как переписать запрос, чтобы он летал.

Это не фантазия. Это результат после 16 модулей, в которых каждая концепция объясняется через код и закрепляется практикой.

ООП, SOLID, LINQ, async/await, DI, EF Core, ASP.NET Core, Docker, Kubernetes - всё, что казалось магией, станет рабочим инструментом.

А бонусом - портфолио проектов: от CLI-утилит и REST API до собственного SaaS с multi-tenancy, JWT и деплоем в Kubernetes под TLS.

Скидка - 58% доступна 48 часов: https://stepik.org/a/282984/

Читать полностью…

C# (C Sharp) programming

C# вопрос с собеседований: скомпилируется ли этот код?

На первый взгляд строка выглядит криво:


order._items.AddRange(items);


Поле _items объявлено как private.

Значит ли это, что доступ к нему разрешён только через this._items?

Нет.

Код скомпилируется.

В C# модификатор private ограничивает доступ типом, а не конкретным экземпляром объекта.

То есть любой код внутри класса Order может обращаться к private-полям любого другого экземпляра Order.

Пример:


public class Order
{
private readonly List<OrderItem> _items = new();

public void CopyItemsFrom(Order other)
{
_items.AddRange(other._items);
}
}


Здесь other._items тоже валиден, потому что мы всё ещё находимся внутри типа Order.

Это часто путают на собеседованиях:
private означает не «доступно только этому объекту», а «доступно только коду внутри этого класса».

В примере это используется в static factory method:


var order = new Order { ... };
order._items.AddRange(items);
return order;


Метод Create находится внутри Order, поэтому он имеет полный доступ к private-состоянию создаваемого экземпляра.

Более интересный вопрос тут даже не в компиляции, а в дизайне.

Такой подход часто встречается в DDD:

* private constructor
* static factory method
* закрытая коллекция _items
* наружу отдаётся IReadOnlyList<OrderItem>
* изменение состояния контролируется внутри агрегата

Но есть нюанс.

_items.AsReadOnly() каждый раз создаёт новый wrapper. Обычно лучше кэшировать read-only view или возвращать IReadOnlyCollection<T>, если индексатор не нужен.

Ещё важнее: фабрика должна не просто копировать items, а проверять инварианты:


if (items is null || items.Count == 0)
throw new DomainException("Order must contain at least one item.");


Иначе получается не DDD entity, а просто объект с красивой фабрикой.

Да, код компилируется.
Потому что private в C# работает на уровне типа, а не экземпляра.

А хороший senior-вопрос здесь такой:
скомпилируется ли код - это база.
А вот защищает ли этот Order свои инварианты - уже архитектура.

Читать полностью…

C# (C Sharp) programming

OptimizerDuck - open-source утилита, после которой CCleaner уже не нужен

OptimizerDuck собирает в одном приложении 30+ твиков системы: от отключения телеметрии, Copilot, Cortana и рекламного ID до тонкой настройки автозагрузки, служб, питания и задержек ввода.

Укаждой настройки есть рейтинг риска. То есть вы заранее видите, что безопасно применить, а где лучше подумать, вместо классического сценария «нажал всё подряд и потом откатываешь систему».

Что умеет:

* отключать телеметрию Windows, Cortana, Copilot и рекламный ID
* управлять автозагрузкой приложений
* настраивать службы хоста под объём RAM
* включать кастомный план питания для высокой производительности
* снижать задержку клавиатуры для игр
* применять GPU-твики, которые обычно правят вручную через реестр

Все изменения обратимы. Не понравилось, можно откатить назад. можно откатить назад.

https://github.com/itsfatduck/optimizerDuck

Читать полностью…

C# (C Sharp) programming

🖥 Задача


using System;
using System.Collections.Generic;
using System.Threading.Tasks;

var actions = new List<Func<Task>>();

for (int i = 0; i < 3; i++)
{
actions.Add(async () =>
{
await Task.Yield();
Console.Write(i + " ");
});
}

foreach (var action in actions)
{
await action();
}


Что выведет код?

Варианты:


0 1 2
3 3 3
0 0 0
1 2 3

Правильный ответ:

3 3 3

Разбор коротко:

i в for не копируется в каждую лямбду. Все три лямбды захватывают одну и ту же переменную i. Когда цикл закончился, i == 3. Поэтому каждая отложенная async-функция печатает уже финальное значение.

Чтобы получить 0 1 2, нужно создать локальную копию внутри цикла:
```
for (int i = 0; i < 3; i++)
{
int copy = i;

actions.Add(async () =>
{
await Task.Yield();
Console.Write(copy + " ");
});
}
```

Читать полностью…

C# (C Sharp) programming

Алгоритму почти 70 лет, а он до сих пор живёт в ядре Linux.

В 1957 году Wilkes, Wheeler и Gill описали быстрый способ считать количество установленных битов в числе. Не циклом по одному биту, а через маски и арифметику сразу над группами битов.

Идея простая:

- сначала считаем биты парами
- потом группами по 4
- потом по байтам
- в конце умножение собирает сумму в старший байт

Если в процессоре нет инструкции POPCNT, Linux использует похожий подход в __sw_hweight64.

Красивый пример того, как старый битовый трюк пережил десятилетия и всё ещё работает в современном системном коде.

Читать полностью…

C# (C Sharp) programming

🖥 C# задачка с подвохом

Что выведет код?


using System;
using System.Collections.Generic;

var list = new List<Func<int>>();

for (int i = 0; i < 3; i++)
{
int x = i;
list.Add(() => x);
x = 100;
}

foreach (var f in list)
{
Console.Write(f() + " ");
}


A) 0 1 2

😎 100 100 100

C) 3 3 3

D) 0 100 100

Правильный ответ: 😎 100 100 100

Почему так:

Внутри каждой итерации создаётся новая локальная переменная x, и именно её захватывает лямбда. Кажется, что ответы должны быть 0 1 2, потому что x получает значение i.

Но после добавления лямбды переменная x всё ещё та же самая захваченная переменная. Потом мы меняем её на 100.

В итоге каждая лямбда хранит свою отдельную x, но каждая из этих x была изменена на 100.

Читать полностью…

C# (C Sharp) programming

Полезная находка для геймдевов: большая коллекция open-source игр в одном месте.

В репозитории собраны десятки проектов разных жанров. Всё разложено по категориям, у каждой игры есть краткое описание и ссылка на исходники.

Можно смотреть, как устроены реальные игровые проекты, разбирать архитектуру, контрибьютить или просто запускать и играть.

Для тех, кто учится геймдеву, это почти готовая база примеров из живого кода.

https://github.com/bobeff/open-source-games

Читать полностью…

C# (C Sharp) programming

Форма логина и JWT-токен — ещё не безопасность приложения. На практике ошибки в аутентификации и авторизации становятся причиной утечек данных, проблем с доступом и уязвимостей, которые сложно обнаружить до выхода системы в production.

26 мая в 20:00 МСК приглашаем вас на открытый урок курса «C# ASP.NET Core-разработчик». На занятии разберём, как в ASP.NET Core устроены pipeline, middleware и схемы аутентификации. Покажем, как правильно использовать JWT, cookies, claims, роли и policy-based авторизацию для гибкого и безопасного контроля доступа.

Отдельно обсудим типичные ошибки, которые встречаются в production: небезопасное хранение токенов, ошибки настройки схем и проблемы в логике авторизации. Урок будет полезен .NET-разработчикам, которые хотят систематизировать знания по безопасности веб-приложений и увереннее работать с ASP.NET Core в реальных проектах.

Регистрация уже открыта:
https://otus.pw/6I5f/?erid=2W5zFGd7RPP


Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.

Читать полностью…

C# (C Sharp) programming

🖥 C# Roadmap: с нуля до профи

Практическое руководство по росту в C#-разработке. Материал собран для тех, кто хочет получить инженерную глубину, а не просто накликать CRUD по туториалам.

Здесь последовательность изучения, лучшие практики, ресурсы и трезвый разбор того, как работать с ИИ-инструментами и оставаться востребованным.

https://github.com/Develp10/Csharp_Roadmap/

Читать полностью…

C# (C Sharp) programming

⚡️ Один SQL-запрос выполнялся за 298 мс.

Почти такой же - за 0,66 мс.

Разница в 451 раз из-за одной строки.

Ситуация обычная: cursor pagination, сортировка по date DESC, id DESC, лимит на 1000 записей и composite index по (date, id). На первый взгляд, все должно работать быстро.

Но EXPLAIN ANALYZE показывает другое: Postgres вроде бы использует Index Scan, но после этого выкидывает 900 000 строк через Filter.

То есть индекс есть, но запрос все равно тащит слишком много лишнего.

Проблема в условии:

`date < @date OR (date = @date AND id <= @lastId)`

Для разработчика это выглядит логично: сначала сравниваем дату, потом id.

Но для оптимизатора такой OR плохо ложится на composite index. В итоге база не может сразу пойти по нужному диапазону и вынуждена фильтровать огромный кусок данных.

Правильнее записать условие через tuple comparison:

`(date, id) <= (@date, @lastId)`

Смысл тот же, но для Postgres это уже понятный диапазон по составному индексу.

И результат: 298 мс превращаются в 0,66 мс.

Индекс сам по себе ничего не гарантирует.

Важно не только создать индекс, но и написать запрос так, чтобы оптимизатор реально смог его использовать.

Читать полностью…

C# (C Sharp) programming

🖥 На Stepik обновили курс «C# с нуля до профи»

Представьте: через четыре месяца вы открываете чужой .NET-проект и читаете его как книгу.

IServiceCollection не вызывает ступора. async Task<IActionResult> пишется на автомате. Вы точно знаете, почему EF Core сгенерировал именно такой SQL - и как переписать запрос, чтобы он летал.

Это не фантазия. Это результат после 16 модулей, в которых каждая концепция объясняется через код и закрепляется практикой.

ООП, SOLID, LINQ, async/await, DI, EF Core, ASP.NET Core, Docker, Kubernetes - всё, что казалось магией, станет рабочим инструментом.

А бонусом - портфолио проектов: от CLI-утилит и REST API до собственного SaaS с multi-tenancy, JWT и деплоем в Kubernetes под TLS.

Скидка - 58% доступна 48 часов: https://stepik.org/a/282984/

Читать полностью…

C# (C Sharp) programming

Хватит копировать один и тот же unit test

Если тест отличается только входными данными, не нужно плодить десятки одинаковых методов.

В xUnit для этого есть parameterized tests, они же data-driven tests. Вы пишете один тест, а потом прогоняете его на разных наборах данных.

Самый простой вариант - [InlineData(...)], когда параметры можно прямо указать над тестом.

Если данных больше или нужна нормальная типизация, можно вынести их в TheoryData<T> и подключить через [ClassData(typeof(...))].

Смысл простой: меньше копипасты, чище тесты, проще добавлять новые кейсы.

Вместо пяти почти одинаковых тестов - один понятный сценарий и набор входных данных.

Для xUnit это один из тех приемов, который быстро окупается в любом C# проекте.

Читать полностью…

C# (C Sharp) programming

🖥 Unity 6 заходит в эпоху AI-геймдева: ИИ-агент теперь прямо в редакторе

Unity выкатила в открытую бету AI-помощника, который работает не как «чатик сбоку», а как полноценный агент внутри проекта. Он видит контекст сцены, понимает структуру кода и может сам вносить изменения.

Что умеет:

— Plan Mode: разбивает задачу на шаги, пишет код, ищет ошибки и помогает выстроить архитектуру
— Figma-интеграция: можно дать ссылку на макет, а Unity попробует собрать по нему интерфейс
— Генерация ассетов: текстуры, звуки и 3D-объекты можно создавать по текстовому описанию
— Откат изменений: если агент накосячил, правки можно быстро вернуть назад

Для Pro и Enterprise функции уже доступны. В Personal-версии бету можно попробовать через trial.

Геймдев постепенно превращается в работу не только с кодом и сценами, но и с агентами, которые собирают часть проекта по описанию.

А вместе с этим, похоже, нас ждёт новая волна нейрослоп-игр в Steam.

https://unity.com/ru/features/ai?utm_campaign=unity-ai-beta

Читать полностью…

C# (C Sharp) programming

Представь обычную ситуацию.

Пользователь заходит в корзину, добавляет товары, что-то удаляет, меняет количество и оформляет заказ.

В базе у тебя остаётся только финальное состояние. Просто запись “как есть сейчас”. Всё, что происходило до этого, исчезает.

Ты не увидишь, какие товары удаляли, где пользователь сомневался, на каком шаге что-то пошло не так. Для отладки, аналитики и аудита это слепая зона.

Пока у тебя простой CRUD на ASP.NET Core и Entity Framework Core, это может не мешать. Но как только появляются бизнес-процессы посложнее, начинаются проблемы. Нет истории - нет понимания.

Здесь пригодится Event Sourcing.

Вместо того чтобы перезаписывать состояние, ты сохраняешь каждое изменение как отдельное событие. Не “корзина сейчас такая”, а “в корзину добавили товар”, “товар удалили”, “оформили заказ”.

События неизменяемые. Ты их не редактируешь и не удаляешь. Только добавляешь новые.

Каждая сущность превращается в поток событий. У корзины своя последовательность: создали, добавили товар, удалили, оформили заказ.

Текущее состояние собирается из этих событий. В

C# это обычно выглядит как агрегат, который проигрывает события и восстанавливает состояние в памяти. Плюс там же проверяются бизнес-правила перед добавлением новых событий.

Для чтения строятся отдельные модели. Например, через Marten или тот же PostgreSQL. Они обновляются сразу или асинхронно и отдают данные в API.

В итоге у тебя не просто таблица с текущими значениями, а полная история системы. Можно откатиться на любой момент, разобрать баг, посмотреть реальные действия пользователя.

CRUD отвечает на вопрос “что сейчас в базе”.
Event Sourcing отвечает на вопрос “что реально происходило”.

И для сложных систем это уже не архитектурный стиль, а вопрос выживания проекта.

Гайд по эвент-сорсингу

Читать полностью…

C# (C Sharp) programming

🖥 Что выведет код?

Как бы ты почистил этот код?

A - Заменить вложенные if на guard clauses
B - Использовать LINQ для фильтрации и суммы
C - Вынести скидку VIP в отдельный метод
D - Все варианты выше

@csharp_ci

Читать полностью…

C# (C Sharp) programming

✔️ Rate Limiting по пользователю это must have для любого нормального API.

Если ты до сих пор ограничиваешь по IP, у тебя уже есть проблема. Один шумный клиент может легко положить сервис для всех.

Правильный подход это лимиты по User ID. Ты берёшь идентификатор пользователя из контекста и используешь его как partition key.

В итоге каждый пользователь получает свой собственный лимит, нет конфликтов между клиентами, нет ложных блокировок, и API остаётся стабильным даже под нагрузкой.

Плюс это честно, потому что один агрессивный пользователь не влияет на остальных.

В ASP.NET Core это настраивается буквально в пару строк через AddRateLimiter с FixedWindow или SlidingWindow стратегией.

Главная мысль в том, что rate limiting это не только про защиту от атак, это про контроль ресурсов и предсказуемость системы.

Если у тебя есть публичный API и нет нормальных лимитов, это не вопрос если упадёт, это вопрос когда.

Читать полностью…
Subscribe to a channel