Библиотека шарписта | C#, F#, .NET, ASP.NET
22.5K subscribers
2.44K photos
39 videos
85 files
4.64K links
Все самое полезное для C#-разработчика в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/b60af5a4

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Download Telegram
✏️ Как найти два повторяющихся числа в массиве

Вам дан массив nums длиной n+2, содержащий числа от 0 до n-1. Два числа случайным образом появились в списке дважды. Нужно вернуть эти два числа. Например, для входа [0][1][1][2][3][3][4] ответ будет [1][3].

Для решения можно воспользоваться подсчётом количества появлений каждого числа.

Если встретили число во второй раз — записываем его в ответ:
public int[] GetSneakyNumbers(int[] nums)
{
int n = nums.Length;
int[] count = new int[101];
int[] res = new int[2];
int idx = 0;

foreach (var num in nums)
{
count[num]++;
if (count[num] == 2)
{
res[idx] = num;
idx++;
}
}
return res;
}


При помощи вспомогательного массива считаем, сколько раз встречается каждое число, и когда оно появилось второй раз — запоминаем.

➡️ Попробовать решить

🐸 Библиотека шарписта

#dotnet_challenge
Please open Telegram to view this post
VIEW IN TELEGRAM
7🥱4😁1
💲 Как договориться о зарплате: 9 стратегий

В зарплатных переговорах нет универсального сценария. Но есть проверенные стратегии под разные ситуации.
В статье 9 тактик от открытой до «я никуда не тороплюсь» — с готовыми фразами для собеседования.

➡️ Выбирайте свою в зависимости от опыта, позиции и типа компании

🐸 Библиотека шарписта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
☺️ 6 дней труда — пора отдыхать

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

💬 А вы как планируете провести ближайшие дни? Уже отдыхаете или еще у дел? Ждем ваши ответы в комментариях 👇

🐸 Библиотека шарписта

#entry_point
Please open Telegram to view this post
VIEW IN TELEGRAM
💯9😁1
📰 Шестидневные новости

Вспомним, что произошло за 6 рабочих дней.

C# сохраняет популярность

Вышел ежегодный Octoverse от GitHub, в котором отмечается рекордный рост числа разработчиков, активность в проектах с AI и смена лидерства по языкам программирования.

Unity Lite. Простой старт в 3D для всех

Инструмент от Unity для создания интерактивных 3D-сцен без программирования, с удобной навигацией и редактором внутри браузера/.

Нейросети поиграли в покер

Победителем стала модель OpenAI o3 с выигрышем в $36,691 виртуальных денег. Второе место занял Claude Sonnet 4.5, а третье — Grok 4

Новые кастомные агенты Copilot для .NET

GitHub запускает интеллектуальных помощников для оптимизации рабочего процесса .NET‑разработчиков.

Звуки флоппи-дисководов в эмуляторе

🐸 Библиотека шарписта

#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
👨‍💻 Worker Services и Channels вместо сторонних библиотек

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

Обычно первая мысль — взять Hangfire, Quartz или Azure Functions. Но .NET 9 предоставляет встроенные примитивы, которые отлично справляются с этой задачей самостоятельно.

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

Реализуем очередь задач с помощью каналов и фоновые сервисы

Интерфейс и реализация очереди:
public interface IBackgroundTaskQueue
{
ValueTask QueueAsync(Func<CancellationToken, Task> workItem);
ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
}

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, Task>> _queue;

public BackgroundTaskQueue(int capacity = 100)
{
var options = new BoundedChannelOptions(capacity)
{
SingleReader = false,
SingleWriter = false,
FullMode = BoundedChannelFullMode.Wait
};
_queue = Channel.CreateBounded<Func<CancellationToken, Task>>(options);
}

public async ValueTask QueueAsync(Func<CancellationToken, Task> workItem)
=> await _queue.Writer.WriteAsync(workItem);

public async ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken)
=> await _queue.Reader.ReadAsync(cancellationToken);
}


Фоновые сервисы для обработки:
public class BackgroundWorker : BackgroundService
{
private readonly IBackgroundTaskQueue _taskQueue;
private readonly ILogger<BackgroundWorker> _logger;

public BackgroundWorker(IBackgroundTaskQueue taskQueue, ILogger<BackgroundWorker> logger)
{
_taskQueue = taskQueue;
_logger = logger;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Фоновый worker запущен");

while (!stoppingToken.IsCancellationRequested)
{
var workItem = await _taskQueue.DequeueAsync(stoppingToken);
try
{
await workItem(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при выполнении задачи");
}
}

_logger.LogInformation("Worker останавливается...");
}
}


Использование в контроллере:
app.MapPost("/send-email", async (IBackgroundTaskQueue queue) =>
{
await queue.QueueAsync(async token =>
{
await Task.Delay(1000, token); // имитация отправки
Console.WriteLine($"Email отправлен в {DateTime.UtcNow}");
});
return Results.Accepted();
});


Запрос возвращается немедленно, а работа продолжается в фоне. Queue автоматически буферизирует задачи, управляет нагрузкой и применяет обратное давление, если очередь переполнится.

Когда использовать этот подход

Подходит:

• Внутренняя обработка задач в приложении
• Нет нужды в UI-панели мониторинга
• Self-contained сервисы

Возьмите библиотеку, если:

• Нужна распределённая обработка
• Требуется веб-интерфейс для управления
• Задачи должны пережить перезагрузку приложения

➡️ Источник

🐸 Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14
✏️ Задачка с собеса

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

Первый рефлекс новичка — взять квадратный корень и проверить, целое ли число:
(int)Math.Sqrt(num) * (int)Math.Sqrt(num) == num


Но на собесе после этого последует вопрос: «А можете без встроенной функции?» Вот тогда начинается интересное.

Вместо математики используем логику: если x * x = num, то x находится где-то между 1 и num. Сужаем диапазон поиска, пока не найдём точный ответ.

public bool IsPerfectSquare(int num)
{
long left = 1;
long right = num;

while (left <= right)
{
long mid = (left + right) / 2;
long square = mid * mid;

if (square == num)
return true;
else if (square < num)
left = mid + 1;
else
right = mid - 1;
}

return false;
}


Есть ещё метод Ньютона для поиска корня — он даже быстрее для больших чисел:
public bool IsPerfectSquare(int num)
{
long x = num;

while (x * x > num)
{
x = (x + num / x) / 2;
}

return x * x == num;
}


Главное: объясните почему вы выбрали именно этот подход, а не просто скопировали решение. На собесе вас оценивают не только по скорости, а по способности мыслить.

➡️ Попробовать решить

🐸Библиотека шарписта

#dotnet_challenge
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72
👀 Управление доступом в .NET

Если вы работаете с авторизацией в .NET и используете Identity, но всё ещё не совсем понимаете, как правильно организовать систему разрешений — есть видео, которое стоит посмотреть.

В нём конкретный пример: как взять стандартный ASP.NET Core Identity и использовать его для управления доступом. Ничего экзотического — обычная setup с JWT и кастомным authorization handler.

➡️ Посмотреть видео

🐸Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
💬 Три дня работы

Завтра начнётся самая короткая рабочая неделя ноября. Это буквально понедельник, среда и пятница. После шестидневки самое то.

💬 Что будете делать? Успевать выполнить недельные обязанности за три дня? Или три дня будете пытаться начать работать?

🐸Библиотека шарписта

#entry_point
Please open Telegram to view this post
VIEW IN TELEGRAM
⚡️ Пять команд .NET, без которых неудобно

Бывает, нужно быстро собрать, запустить или опубликовать проект без запуска тяжелой IDE, особенно в пайплайне или на сервере разработчика. Для этого хватает нескольких команд из .NET CLI, которые работают одинаково на всех платформах.

Проверить установку и окружение поможет команда dotnet --info, она покажет версии SDK и рантаймов и архитектуру хоста.

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

Запуск приложения через dotnet run объединяет сборку и старт процесса, что эквивалентно кнопке Run в IDE и удобно для ручных проверок локально.

Горячая перезагрузка из терминала через dotnet watch отслеживает изменения файлов и повторно запускает приложение с Hot Reload без ручного рестарта, что ускоряет цикл правка и проверка.

Если сборка ведет себя странно, стоит выполнить dotnet clean, чтобы удалить выходные артефакты и заставить следующий build собрать все заново.

Для развертывания используйте dotnet publish, который соберет релиз и положит готовый к деплою набор файлов в папку publish, включая веб приложения и сервисы.

🐸Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
7
🤨 Когда помощник становится врагом

Представьте, что вы отправили друга в магазин с деньгами на общий счёт. Он может потратить их на что угодно, при этом никому не отчитываясь. Вот примерно так же работает static с изменяемым состоянием. Удобно? Да. Безопасно? Совсем нет.

Почему static плохо сочетается с данными

Static — это ключевое слово, которое любят новички и используют для удобства. А потом из этого вырастают проблемы, которые отъедают часы отладки. Главная беда в том, что статические поля существуют всё время работы программы и доступны отовсюду.

Четыре золотых правила

1. Статические поля могут быть только для чтения. Лучше — константы.

2. Статические методы должны работать как математические функции: дали параметры — получили результат. Никаких побочных эффектов, никаких изменений состояния. Например: Select, Where, First из LINQ — это всё статические методы расширения, которые не трогают исходную последовательность.

3. Если в классе есть методы, которые не используют поля экземпляра, эту логику лучше вынести в отдельный статический класс-помощник. Это делает код чище, тесты проще.

4. Если вы создаёте статическое поле, пусть оно указывает на что-то, что не меняется. На объект конфигурации? Хорошо. На список данных, который вы потом модифицируете? Катастрофа.

Когда static — ваш друг

• Вспомогательные классы с чистыми функциями

Создайте статический класс StringUtils с методом static string ToPascalCase(string input). Нет состояния, нет побочных эффектов, нет проблем. Это хорошее использование.

• Методы расширения для преобразований

Select, Where и компания — статические методы расширения, которые берут данные, преобразуют их и возвращают новые. Функциональный подход, никакого волшебства.

• ThreadStatic для действительно отдельного состояния

Если каждому потоку нужно своё состояние, можно использовать ThreadStatic. Но даже здесь нужна осторожность — каждый поток всё равно должен управлять своим состоянием.

Передайте зависимость через конструктор, используйте DI-контейнер, создайте объект на сессию. Ваш будущий я, сидящий в отладчике в три утра, скажет вам спасибо.

🐸Библиотека шарписта

#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
Гид по Redis в C# ASP.NET: ускоряем приложения и снижаем нагрузку на базу данных.

Redis — быстрая база данных в памяти, которая помогает масштабировать системы и ускорять доступ к данным. На открытом вебинаре курса OTUS C# ASP.NET Core разработчик Андрей Сорокин покажет, как интегрировать Redis в ASP.NET Core 8 и внедрить кэширование в реальных проектах.

📌 12 ноября, 20:00
Гид по Redis в C# ASP.NET
— настройка Redis в Docker
— кэширование ответов API
— хранение данных для быстрого доступа
— ускорение обработки запросов и снижение нагрузки на БД

Вебинар бесплатный и будет полезен C#-разработчикам, архитекторам и тимлидам, которые хотят повысить производительность приложений и упростить масштабирование.

👉 Регистрируйтесь: https://clc.to/YMHL9A

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
1
📎 Когда тип спасает

Представьте, что вы пришли в магазин и продавец говорит: «Вот вам что-то. Не знаю что. Может быть, помидоры, может быть, кирпич, может быть, счастье. Узнаете, когда вернётесь домой». Вот такое же ощущение от IActionResult без типов.

Проблема с IActionResult:
[HttpGet("{id:guid}")]
public async Task<IActionResult> GetById(Guid id, ISender mediator, CancellationToken ct)
{
var dto = await mediator.Send(new GetUserQuery(id), ct);
return dto is null ? NotFound() : Ok(dto);
}


Возвращаемый тип — IActionResult. Просто интерфейс. Ничего конкретного. Кто читает этот код, не знает, что именно вернётся. Может быть UserDto, может быть ошибка, может быть что угодно.

Вот так выглядит сгенерированная Swagger документация:
{
"responses": {
"200": { "description": "Success" }
}
}


Никакой информации о схеме. Кто использует ваш API, не знает, какие поля будут в ответе. IDE не может подсказать структуру. Тесты пишутся вслепую.

Решение: ActionResult<T>
[HttpGet("{id:guid}")]
public async Task<ActionResult<UserDto>> GetById(Guid id, ISender mediator, CancellationToken ct)
{
var dto = await mediator.Send(new GetUserQuery(id), ct);
return dto is null ? NotFound() : Ok(dto);
}


Возвращаемый тип — ActionResult<UserDto>. Конкретно и ясно. Читающий код понимает мгновенно: метод возвращает UserDto при успехе или ошибку. Swagger генератор видит типы и строит правильную документацию.

IActionResult можно использовать, когда метод не возвращает тело, к примеру ответ 204.

🐸Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
6