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

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

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

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

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Download Telegram
✏️ Сокращаем код

Collection expressions — удобный синтаксис для создания и инициализации коллекций и массивов с помощью квадратных скобок и элементов, разделённых запятыми. Можно использовать spread-элементы (..) для вставки содержимого других коллекций внутрь новой.

Пример:
int[] odds = [1, 3, 5, 7];

string[] vowels = ["a", "e", "i", "o", "u"];
string[] consonants = ["b", "c", "d", "f"];
string[] alphabet = [..vowels, ..consonants, "y"];


С помощью выражений коллекций можно легко создавать массивы, списки, Span и другие коллекторные типы. Появились они в C# 12.

🔹 Экспресс-курс «Математика для Data Science»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
🤨 Как искусственный интеллект помогает писать тесты

Создание качественных модульных тестов — важный, но утомительный и затратный процесс. GitHub Copilot Testing для .NET упрощает эту задачу, автоматически генерируя, собирая и выполняя тесты прямо в вашем рабочем процессе.

Как начать использовать

1. Установите последнюю версию Visual Studio 2026 Insiders и получите лицензию GitHub Copilot

2. Включите функцию GitHub Copilot Testing через настройки (Tools > Options > GitHub > Copilot > Testing

3. Откройте проект или решение на C# и убедитесь, что оно успешно собирается

4. В чате Copilot напишите команду @Test #target, где #target — имя метода, класса, файла, проекта, решения или #changes для git diff

5. Copilot автоматически проанализирует код, создаст проект с тестами (если его нет), сгенерирует, соберёт и выполнит тесты.

Результаты отображаются в Test Explorer и в окне чата, где вы увидите статистику по числу тестов, изменениям в покрытии кода и рекомендации по устранению «тестируемых» пробелов.

🔹 Специалист по ИИ
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7😁1🤩1
🛠 Структурные опциональные параметры в F# 10

В F# 10 появилась возможность использовать структурный тип ValueOption<'T> для опциональных параметров. Это позволяет избежать выделения памяти в куче.

Теперь, применяя атрибут [<Struct>], можно указать компилятору использовать ValueOption<'T> — структуру, которая хранится на стеке и не требует дополнительных аллокаций.

Раньше:
type X() =
static member M(?x: string) =
match x with
| Some v -> printfn "Some %s" v
| None -> printfn "None"


Теперь с F# 10:
type X() =
static member M([<Struct>] ?x: string) =
match x with
| ValueSome v -> printfn "ValueSome %s" v
| ValueNone -> printfn "ValueNone"


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

🔹 Экспресс-курс «Математика для Data Science»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
2
⭐️ Логирование исключений с помощью фильтров

Фильтры исключений позволяют выполнить код при срабатывании catch, но при этом не перехватывать исключение.

Пример:
try 
{
await work();
}
catch (Exception ex) when (Log(ex))
{
// этот блок не выполняется, так как Log возвращает false
}

static bool Log(Exception ex)
{
// логируем исключение
return false;
}


Метод Log вызывается один раз при исключении, логирует его и возвращает false, чтобы исключение продолжило всплывать дальше без перехвата.

🔹 Алгоритмы и структуры данных
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔12😁42👾1
🤩 Типизированные вычислительные выражения в F# 10 без скобок

В F# 10 упростили синтаксис для аннотирования типов в вычислительных выражениях. Теперь можно добавлять типы в let!, use! и and! без необходимости использовать дополнительные скобки вокруг идентификаторов.

ньше для указания типа в вычислительном выражении приходилось писать так:
let! (x: int) = fetchValue()


Сейчас можно написать короче:
let! x: int = fetchValue()


Если вы часто работаете с async, task или другими вычислениями, это изменение вы оцените.

🔹 Алгоритмы и структуры данных
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
3🤔1🥱1
👨‍💻 Обработка ошибок в .NET minimal API

При разработке API важно правильно и понятно передавать клиентам информацию о возникших ошибках.

Одним из удобных способов сделать это в .NET minimal API является использование встроенного метода Results.Problem. Он возвращает объект с подробностями ошибки в стандарте ProblemDetails, что упрощает клиентам обработку ответа.

Пример:
app.MapGet("/users/{id}", async (string id, IUserRepo repo) =>
{
if (!Guid.TryParse(id, out var guid))
return Results.Problem("Invalid id", statusCode: 400);

var user = await repo.Find(guid);
return user is null ? Results.NotFound() : Results.Ok(user);
});


В этом коде при неверном формате id возвращается ProblemDetails с кодом 400, если пользователь не найден — 404, иначе 200 с данными.

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
3
💡 Tail-call оптимизация в вычислительных выражениях F# 10

В F# 10 появилась важная возможность оптимизировать использование вычислительных выражений с помощью поддержки tail-call оптимизации для ключевых вызовов return!, yield! и do!.

Теперь компилятор распознаёт, когда эти вызовы находятся в хвостовой позиции, и, если реализация билдера поддерживает специальные методы ReturnFromFinal, YieldFromFinal и им подобные, он применяет оптимизацию tail call. Это позволяет выполнять вызовы без дополнительного роста стека.

🔹 Основы IT для непрограммистов
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👾2
⚡️ Batch-обработка с помощью Chunk

Если нужно обработать коллекцию по частям — например, выгрузить данные пакетами, есть решение: метод Chunk. Он создаёт из исходного списка последовательность подсписков одинакового размера.

Пример:
foreach (var batch in items.Chunk(100))
{
await SaveBatch(batch);
}


Chunk тут удобен тем, что не требует писать циклы с индексами и сложную логику по разбиению. Просто задайте размер пакета, и метод сделает всё за вас.

🤌 Бонусы для подписчиков:
Скидка 40% на все курсы Академии
Розыгрыш Apple MacBook
Бесплатный тест на знание математики

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍202🥰2❤‍🔥1
💻 Поддержка паттерна discard в use! в F# 10

Раньше в use! вычислительных выражениях нельзя было указать _ для игнорирования результата, что заставляло создавать ненужные имена переменных, например, __ или _ignored.

Теперь можно прямо написать:
use! _ = acquireResourceAsync()


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

🤌 Бонусы для подписчиков:
Скидка 40% на все курсы Академии
Розыгрыш Apple MacBook
Бесплатный тест на знание математики

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
3
👨‍💻 DbContext в ASP.NET Core лучше оставлять scoped

В ASP.NET Core есть негласное правило DbContext живет ровно столько, сколько живет HTTP запрос. Эту модель Microsoft прямо закладывает в документацию, ведь DbContext задуман как короткоживущий объект под одну единицу работы одну бизнес операцию и один вызов SaveChanges.

Когда вы регистрируете контекст так:
builder.Services.AddDbContext<AppDb>(opt =>
opt.UseNpgsql(connString));

контейнер DI по умолчанию регистрирует AppDb с временем жизни Scoped. Это значит новый экземпляр создается на каждый запрос и шарится только между сервисами внутри этого запроса.

Если сделать DbContext Singleton вы получите общий экземпляр на все запросы сразу и это прямой путь к гонкам, утечкам и странным багам.

🤌 Бонусы для подписчиков:
Скидка 40% на все курсы Академии
Розыгрыш Apple MacBook
Бесплатный тест на знание математики

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍64👾1
✏️ Запрет псевдо-вложенных модулей внутри типов в F# 10

В F# 10 добавили важное правило: теперь нельзя объявлять модуль внутри определения типа с тем же уровнем отступа, как сам тип.

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

Пример из старого кода:
type U =
| A
| B
module M = // на самом деле не вложенный модуль
let f () = ()


Правильный код:
type U =
| A
| B

module M =
let f () = ()


Это предотвращает частую ошибку, когда модуль кажется «вложенным» в тип, но на самом деле не является таковым.

🔸 Математика для Data Science
🔸 Получить консультацию менеджера
🔸 Сайт Академии 🔸 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4👾2🌚1
🔍 Устаревший синтаксис в F# 10

Раньше F# позволял опускать ключевое слово seq при создании последовательностей, что выглядело так:
{ 1..10 } |> List.ofSeq  // неявная последовательность


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

Теперь компилятор рекомендует явно писать seq, чтобы сделать код однозначным и понятным:
seq { 1..10 } |> List.ofSeq


Сейчас это предупреждение, а не ошибка, чтобы дать время адаптироваться и исправить код. Но в будущих версиях F# это может превратиться в ошибку.

🔸 AI-агенты для DS-специалистов
🔸 Получить консультацию менеджера
🔸 Сайт Академии 🔸 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🛠 Строгая проверка назначения атрибутов в F# 10

В F# 10 компилятор стал жёстко проверять, что атрибуты применяются только к тем конструкциям, для которых они предназначены. Это касается функций, значений, объединений, конструкторов, структур, классов и других элементов.

Раньше F# позволял неявно применять атрибуты к неподходящим целям без предупреждений. Из-за этого возникали баги, например:

• Тестовые атрибуты не работали, если функция не имела (), и тесты не запускались

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

Пример такого кода, который никак не работал:
[<Fact>]
let ``this is not a function`` = // никак не запускался тест
Assert.True(false)


Теперь компилятор выдаёт предупреждение при неверном применении атрибутов:
[<Fact>]
//^^^^ предупреждение FS0842: атрибут нельзя применять к свойству, полю и т.п.
let ``works correctly`` =
Assert.True(true)


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

🔹 Алгоритмы и структуры данных
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰2🌚2👍1
🛠 .NET MAUI и работа с возрастом

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

Да, это затрагивает несколько штатов в США, но стоит держать руку на пульсе.

.NET MAUI предоставляет удобный способ решения этой задачи с помощью единого интерфейса IAgeSignalService и трёх платформо-специфичных реализаций:

• Для Android используется Google Play Age Signals API, который возвращает пять статусов в зависимости от ситуации: от подтверждённого возраста до ожидания одобрения опекуна.

• На iOS применяется Apple Declared Age Range API, работающий на устройствах с iOS 26 и выше, отображающий возрастной диапазон и информацию о том, кто его подтвердил — сам пользователь или опекун.

• Windows предлагает Windows Age Consent API с упрощённой классификацией пользователей на три категории: ребёнок, несовершеннолетний и взрослый.

Главное преимущество — единая точка интеграции и адаптация под каждый API за счёт условной компиляции и инъекции зависимостей. Достаточно подключить сервис в MauiProgram, чтобы обеспечить проверку возраста на нужной платформе.

➡️ Блог Microsoft

🔹 AI-агенты для DS-специалистов
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍3
⚙️ Используйте AsNoTracking() для запросов только на чтение

Если нужно получить данные из базы без их изменения, лучше использовать AsNoTracking():
var posts = await db.Posts.AsNoTracking()
.Where(p => p.Published)
.ToListAsync(ct);


Метод AsNoTracking() говорит Entity Framework не отслеживать изменения для полученных объектов.

🔹 Практический интенсив «Архитектуры и шаблоны проектирования»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🥱6
👨‍💻 Поддержка and! в task-вычислениях F# 10

В F# 10 библиотека FSharp.Core получила улучшение — поддержку оператора and! в вычислительном выражении task.

Раньше, чтобы ждать несколько задач параллельно, нужно было либо ждать их последовательно:
task {
let! a = fetchA()
let! b = fetchB()
return combineAB a b
}


Либо использовать Task.WhenAll для ожидания сразу всех:
task {
let ta = fetchA()
let tb = fetchB()
let! results = Task.WhenAll([| ta; tb |])
return combineAB ta.Result tb.Result
}


Первый вариант простой, но последовательный, второй — параллельный, но сложнее по синтаксису.

Теперь с оператором and! можно одновременно ждать несколько задач легко и понятно:
task {
let! a = fetchA()
and! b = fetchB()
return combineAB a b
}


Это сочетает простоту первого примера с параллельным исполнением из второго. Код становится компактным и выразительным.

🔹 Практический интенсив «Архитектуры и шаблоны проектирования»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰2
🔄 Отмена запросов в EF

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

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

В Entity Framework для управления отменой используется CancellationToken. Его можно передавать в асинхронные методы, например:
await db.SaveChangesAsync(ct);


Переданный CancellationToken позволяет прервать выполнение метода, если операция была отменена.

🔹 Математика для Data Science
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰5👍2
⚙️ Как повысить надёжность конфигурации

В современных приложениях важно не только загрузить настройки из конфигурации, но и убедиться, что они корректны. В .NET для этого есть удобный паттерн — Typed Options с встроенной валидацией.

Пример регистрации опций с проверкой данных:
builder.Services.AddOptions<AppOptions>()
.BindConfiguration("App")
.ValidateDataAnnotations() // Валидация по атрибутам из System.ComponentModel.DataAnnotations
.Validate(o => Uri.IsWellFormedUriString(o.ApiBaseUrl, UriKind.Absolute),
"ApiBaseUrl must be absolute") // Дополнительная кастомная проверка
.ValidateOnStart(); // Проверка при старте приложения


Что здесь происходит:

• Конфигурация из секции App автоматически связывается с классом AppOptions.

• Включена проверка на основе Data Annotations — атрибуты вроде [Required], [Range] в AppOptions валидируются автоматически.

• Добавлена кастомная валидация, которая гарантирует, что значение ApiBaseUrl — корректный абсолютный URI.

ValidateOnStart() заставляет приложение валидировать настройки сразу при запуске, а не при первом использовании.

🔹 Специалист по ИИ
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍143🔥1
⚡️ 100 RPS на всё приложение

Rate limit — это простой способ защитить API от всплесков нагрузки, случайных «шторма» с клиента и банального DDoS по честным endpoint’ам.

В примере ниже на всё приложение вешается глобальный лимитер:
builder.Services.AddRateLimiter(o =>
{
o.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(ctx =>
RateLimitPartition.GetFixedWindowLimiter("global", _ =>
new FixedWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromSeconds(1)
}));
});

app.UseRateLimiter();


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

Дальше от этого базового варианта легко прийти к более тонким настройкам: отдельные лимиты на публичные и внутренние маршруты, разделение по API-ключу, IP или пользователю, своя политика ответа и логирование с метриками.

🔹 Алгоритмы и структуры данных
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍204🔥2
📩 Быстрый антиспам

Для .NET есть готовый клиент Cloudmersive Spam Detection API который умеет проверять текстовые поля. Вместо того чтобы вручную обучать модель для спама можно отдать эту задачу готовому облачному сервису.

Для работы с API нужно поставить NuGet пакет Cloudmersive.APIClient.NET.Spam.

После установки достаточно прописать ключ API и создать экземпляр клиента:
using Cloudmersive.APIClient.NET.Spam.Client;
using Cloudmersive.APIClient.NET.Spam.Api;
using Cloudmersive.APIClient.NET.Spam.Model;

public class SpamChecker
{
private readonly SpamDetectionApi _api;

public SpamChecker(string apiKey)
{
// глобальная конфигурация
Configuration.Default.AddApiKey("Apikey", apiKey);
_api = new SpamDetectionApi();
}
}


Базовый сценарий — проверить строку и понять спам это или нет. API предоставляет метод для AI проверки текста и возвращает набор флагов:
public async Task<bool> IsSpamAsync(string text)
{
var request = new SpamDetectionAdvancedRequest
{
InputString = text,
Model = "Advanced",
// политика что считаем допустимым
AllowUnsolicitedSales = false,
AllowPromotionalContent = false,
AllowPhishing = false
};

SpamDetectionAdvancedResponse resp =
await _api.SpamDetectionAdvancedAsync(request);

// если сервис считает текст спамом реагируем
return resp.ContainsSpam ||
resp.ContainsUnsolicitedSales ||
resp.ContainsPhishingAttempt;
}


Ответ модели позволяет различать продажные сообщения, промо контент и фишинг, а не только «спам не спам».

➡️ Документация

🔹 Практический интенсив «Архитектуры и шаблоны проектирования»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰3🔥1🤔1