Библиотека шарписта | C#, F#, .NET, ASP.NET
21.7K subscribers
2.89K photos
45 videos
91 files
5.35K links
Все самое полезное для C#-разработчика в одном канале.

Наши курсы: https://clc.to/y3LDtw

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

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

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Download Telegram
📢 Навигация по каналу

Чтобы не теряться в потоке постов, собрали удобную навигацию по рубрикам:

#sharp_view — короткие и полезные посты с кодом, best practices, фишки C#, сравнение подходов, code snippets и разбор багов

#il_люминатор — глубокие технические разборы: архитектурные паттерны, производительность, устройство .NET, CLR, GC, JIT и сложные концепции

#async_news — релизы .NET, обновления IDE, анонсы конференций, дайджесты и другие важные новости экосистемы

#entry_point — опросы, холивары, вопросы подписчикам, истории из практики и обсуждения с сообществом

#dotnet_challenge — задачи по C# и .NET, вопросы с собеседований, поиск ошибок в коде и интерактивные викторины

#схема — инфографика, диаграммы, шпаргалки, дорожные карты и визуальное объяснение сложных тем

#garbage_collector — мемы, юмор и забавные истории из жизни .NET-разработчиков

🔈 Используйте рубрики для быстрого поиска интересующих материалов и не пропускайте новые публикации.

🐸 Библиотека шарписта
Please open Telegram to view this post
VIEW IN TELEGRAM
7
💡 Если свойству нужна небольшая логика, больше не обязательно заводить отдельное поле

Раньше приходилось писать так:


private string _email;

public string Email
{
get => _email;
set => _email = value.Trim().ToLowerInvariant();
}


Начиная с C# 14 можно использовать field — ссылку на автоматически сгенерированное backing field:


public string Email
{
get;
set => field = value.Trim().ToLowerInvariant();
}


Подходит для:

валидации значений
нормализации данных
INotifyPropertyChanged
небольшой логики в get/set

⚠️ Если в классе уже есть член с именем field, внутри аксессора приоритет получит новое ключевое слово. Для обращения к своему члену используйте @field или this.field.

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
11
This media is not supported in your browser
VIEW IN TELEGRAM
🎓 Где потренировать C# бесплатно

Sololearn предлагает интерактивный курс по C# среднего уровня с практическими заданиями и встроенной AI-проверкой решений.

В программе:

— массивы
— ООП
— структуры и enum
— исключения
— работа с файлами
— generics


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

🔗 Ссылка

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6🤔2
💡 StartsWith('s') лучше, чем StartsWith("s")

Если ищете один символ, используйте перегрузку с char:


text.StartsWith(’s’);


вместо:


text.StartsWith(«s»);


То же самое касается:


text.EndsWith('s');
text.IndexOf(’s’);


Перегрузки с char обычно немного эффективнее и сразу показывают, что поиск идёт по одному символу.

📌 Для одного символа — char, для строки или подстроки — string.

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84🥱4
🧩 Проверка аргументов на null в современном C#

До .NET 6 проверки обычно выглядели так:


if (arg is null)
throw new ArgumentNullException(nameof(arg));


Сейчас для этого есть встроенный метод:

ArgumentNullException.ThrowIfNull(arg);


Что он даёт:

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

Например:

 public UserService(IRepository repository)
{
ArgumentNullException.ThrowIfNull(repository);

_repository = repository;
}


Под капотом используется специальная реализация для guard clauses, поэтому этот вариант не только короче, но и хорошо оптимизируется рантаймом.

Используете ThrowIfNull() или по привычке всё ещё пишете if (arg is null)

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
14👍6🥱3
💡 Пагинация в EF Core: Skip/Take не всегда лучший выбор

Самый популярный вариант пагинации в EF Core выглядит так:


var customers = await dbContext.Customers
.AsNoTracking()
.Where(c => c.IsActive)
.OrderBy(c => c.Id)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToListAsync();


🔵 Под капотом EF Core генерирует SQL с OFFSET/FETCH:


SELECT *
FROM Customers
ORDER BY Id
OFFSET 200 ROWS
FETCH NEXT 100 ROWS ONLY


Для небольших таблиц этого обычно достаточно.

❗️ Но есть нюанс: чем дальше страница, тем больше строк СУБД приходится пропускать перед возвратом результата.
Поэтому для больших таблиц и бесконечной прокрутки часто используют Keyset Pagination:


var customers = await dbContext.Customers
.Where(c => c.Id > lastSeenId)
.OrderBy(c => c.Id)
.Take(pageSize)
.ToListAsync();


Такой подход не требует пропускать тысячи строк и обычно масштабируется заметно лучше.

📌 Простая навигация по страницам → Skip/Take
📌 Большие таблицы и высокая нагрузка → Keyset Pagination

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍145🔥5🤔3
pattern matching in csharp.jpg
69.9 KB
❗️ Pattern Matching — одна из тех возможностей C#, которая делает код заметно чище

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

На картинке — простой пример, который стоит взять на вооружение, если ещё пишете код «по-старому» 👀

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🥱6🔥1
⭐️ Автоматическая регистрация Minimal API через DI

Вместо того чтобы вручную вызывать десятки MapGet() и MapPost(), можно зарегистрировать все endpoint автоматически.

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

1️⃣ каждый endpoint реализует общий интерфейс;
2️⃣ приложение находит все реализации через DI;
3️⃣ при запуске вызывает Map() для каждой.

В результате Program.cs сводится буквально к двум строкам:


builder.Services.AddEndpoints(typeof(Program).Assembly);

app.MapEndpoints();


Чем больше проект, тем заметнее становится преимущество такого подхода.

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
4🥰4🤔2💯2
📍 Task.WhenAll: когда нужно дождаться всех задач

Если несколько операций не зависят друг от друга, не запускайте их по очереди. Запустите сразу все и дождитесь завершения.


var usersTask = LoadUsersAsync(ct);
var ordersTask = LoadOrdersAsync(ct);
var catalogTask = LoadCatalogAsync(ct);

await Task.WhenAll(usersTask, ordersTask, catalogTask);

var users = await usersTask;
var orders = await ordersTask;
var catalog = await catalogTask;


Такой подход позволяет выполнять операции параллельно и уменьшает общее время ожидания.

💡 Несколько советов:

— передавайте CancellationToken во все методы;
— если операций очень много, ограничивайте параллелизм через SemaphoreSlim;
— Task.WhenAll завершится с ошибкой, если хотя бы одна из задач завершилась исключением.

Используйте WhenAll, когда итоговый результат нужен только после завершения всех операций.

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
📌 Списочные паттерны. Разбираем коллекции прямо в switch

Проверка коллекций часто превращается в цепочку условий: сначала Length, потом обращения по индексам, затем ещё несколько if.

В C# 11 появились списочные паттерны (List Patterns), которые позволяют описать форму коллекции прямо в switch.

🅰️ Квадратные скобки задают структуру, .. означает «любое количество элементов», а var позволяет сразу получить нужные значения.


static string Describe(int[] numbers) => numbers switch
{
[] => "пусто",
[var single] => $"один элемент: {single}",
[var first, var second] => $"два: {first} и {second}",
[var first, .., var last] => $"первый {first}, последний {last}",
};


Каждая ветка описывает форму данных, а не последовательность проверок. Не нужно вручную проверять Length и обращаться к элементам по индексам.

🅰️ Особенно удобно разбирать аргументы командной строки или результат Split().


static string Route(string[] args) => args switch
{
["run", var file] => $"запускаем {file}",
["build", .. var rest] => $"сборка с флагами: {string.Join(", ", rest)}",
_ => "неизвестная команда",
};


Обратите внимание на .. var rest: оператор среза не только пропускает элементы, но и позволяет сразу получить их в отдельную коллекцию. Списочные паттерны работают с массивами, списками и другими типами, которые поддерживают индексатор и имеют Length или Count.

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥22
📍 Почему TryParse() лучше, чем Parse() внутри try/catch

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


try
{
var age = int.Parse(input);
SaveAge(age);
}
catch
{
ShowError();
}


🔜 Намерение понятнее выразить через TryParse():


if (int.TryParse(input, out var age))
{
SaveAge(age);
}
else
{
ShowError();
}


TryParse() сразу показывает: преобразование может не удаться, и этот результат предусмотрен логикой программы. Используйте его для форм, query-параметров, настроек, файлов и других внешних данных.

📌 Ожидаемая ошибка — явная проверка. Исключение — действительно исключительная ситуация.

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱94
😎 Новый тип Lock в .NET 9. Пора забыть про object?

В .NET 9 появился специальный тип System.Threading.Lock, созданный именно для синхронизации.


private readonly Lock _sync = new();

public void Add(int x)
{
lock (_sync)
{
_items.Add(x);
}
}


Синтаксис lock не изменился, но компилятор распознаёт тип Lock и использует его напрямую, без перехода через Monitor. Это делает код более явным и позволяет снизить накладные расходы.

При необходимости блокировку можно взять и без оператора lock:


using (_sync.EnterScope())
{
_items.Add(x);
}


⚠️ Важно: не приводите Lock к object. В этом случае компилятор предупредит, а оператор lock снова будет работать через старый механизм на базе Monitor.

Для нового кода System.Threading.Lock — рекомендуемый способ реализации взаимного исключения в .NET 9 и новее.

📍 Навигация: ВакансииЗадачиСобесы

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍28👏42