Структуры передаются по значению — это знают все. Но копия может появиться и там, где её совсем не ожидаешь.
Представьте структуру с обычным, не readonly, методом. Если она находится в readonly-контексте, например в readonly поле или приходит через in, компилятору приходится защищать значение от изменения. При вызове такого метода он может создать защитную копию структуры.
public readonly struct Point
{
public int X { get; }
public int Y { get; }
public int Sum() => X + Y;
}
Можно пометить readonly и отдельные методы или свойства, если всю структуру сделать неизменяемой нельзя.
in при этом позволяет передавать большую структуру по ссылке без обычного копирования, а readonly-члены помогают избежать защитных копий при работе с такой ссылкой.
Если структура концептуально неизменяемая, readonly struct — хороший выбор по умолчанию. А для больших структур in может снизить стоимость передачи, но его эффект зависит от конкретного сценария
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥2👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Не нужен онлайн-конвертер. Копируете JSON и в Visual Studio выбираете:
Edit → Paste Special → Paste JSON As Classes
IDE сама сгенерирует классы, включая вложенные объекты и массивы.
Особенно удобно, когда нужно быстро разобраться с ответом незнакомого API или сделать DTO для прототипа.
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🤩19🥱12❤2😁1
Проверки диапазонов в C# легко превращаются в цепочки сравнений с && и ||. Паттерны позволяют записать их компактнее.
С C# 9 условия можно комбинировать прямо внутри pattern matching:
string Grade(int score) => score switch
{
< 0 or > 100 => "некорректно",
>= 90 => "отлично",
>= 60 and < 90 => "нормально",
_ => "плохо",
};
not особенно удобен для проверок:
if (value is not null)
Process(value);
if (obj is not string)
return;
Паттерны можно комбинировать и с проверкой свойств:
bool IsAdultAdmin(User u) =>
u is { Age: >= 18, Role: "admin" };
Вместо нескольких if получаем одно выражение, где условие читается почти как обычная фраза.
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤6🌚3
При await .NET по умолчанию старается продолжить выполнение в захваченном контексте. Например, в UI-приложении это позволяет после await снова работать с UI-потоком. Но библиотеке обычно всё равно, в каком контексте продолжать работу. Поэтому там часто пишут:
var data = await httpClient
.GetStringAsync(url)
.ConfigureAwait(false);
ConfigureAwait(false) говорит: не нужно возвращать продолжение в исходный контекст.
Есть и классический сценарий с deadlock:
var result = GetDataAsync().Result;
Если GetDataAsync() после await пытается вернуться в занятый контекст, продолжение не может выполниться, а .Result не может завершиться.
В ASP.NET Core собственного SynchronizationContext для запросов нет, поэтому классическая проблема с .Result и захватом контекста там не возникает по этой причине.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
💯6👍4
Раньше при работе с C#-интерфейсами, где базовый слот закрыт через дефолтную реализацию интерфейсов, F# всё равно требовал явно реализовать оба интерфейса.
Теперь достаточно реализовать только производный интерфейс.
public interface IA { int M(); }
public interface IB : IA {
new int M();
int IA.M() => this.M() + 100; // DIM покрывает слот IA.M
}
type C() =
interface IB with member _.M() = 42
(C() 😆 IB).M() // 42
(C() 😆 IA).M() // 142 — DIM перенаправляет: this.M() + 100
Улучшение работает не только для простых случаев. Поддерживается ромбовидное наследование, дженерик-интерфейсы, свойства, события, структуры и объектные выражения.
Для включения нужен флаг --langversion:preview.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
😁4❤2🔥2🥱2
Вы оптимизировали базу данных. Ничего не изменилось. Оптимизировали сетевые вызовы. Всё ещё медленно.
Оказалось, приложение создаёт новый JsonSerializerOptions в каждом запросе. Это уничтожает встроенный кеш метаданных System.Text.Json и превращает JSON сериализацию в дорогую операцию, которая повторяется сотни раз в секунду под нагрузкой.
JsonSerializerOptions это не просто настройки. Это место, где System.Text.Json хранит кэшированные метаданные о том, как сериализовать и десериализовать типы.
Каждый новый экземпляр JsonSerializerOptions начинает с пустого кеша. System.Text.Json должна заново анализировать тип, строить информацию о сериализации, кешировать её. Потом запрос закончился и всё выбросилось.
Следующий запрос приходит. Новый экземпляр. Пустой кеш снова. Всё сначала.
Microsoft так серьёзно относится к этому, что добавили анализатор CA1869, который явно предупреждает: не создавайте JsonSerializerOptions локально в горячих путях.
string ToJson(object value)
{
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)
{
WriteIndented = false
};
return JsonSerializer.Serialize(value, options);
}
Под нагрузкой это выглядит как:
— CPU растёт без видимых причин
— Задержка становится нестабильной, p99 скачет
— Профилер показывает JSON сериализацию как горячую точку
— А вы не понимаете почему, если оптимизировали всё остальное
public static class JsonDefaults
{
public static readonly JsonSerializerOptions Web = new(JsonSerializerDefaults.Web)
{
WriteIndented = false,
Converters = { new JsonStringEnumConverter() }
};
}
Используем кеш, никаких затрат
return JsonSerializer.Serialize(payload, JsonDefaults.Web);
Одна переменная, кеш остаётся тёплым, производительность стабильной.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25🤔2
Часто новички в функциональном программировании думают, что сделали иммутабельный код. Берут список, вызывают ToList() или Select() и радуются новому списку. Но в C# это ловушка.
Проблема в ссылочных типах. var copy = original.ToList() создаёт новый List, но все элементы внутри — те же самые объекты. Меняете свойство через copy, и оригинал тоже меняется.
Правило трёх:
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
В EF Core 9 появились UseSeeding() и UseAsyncSeeding(), а в актуальном EF Core 10 это уже рекомендуемый Microsoft способ для обычного заполнения базы начальными данными.
optionsBuilder
.UseSeeding((context, _) =>
{
if (!context.Set<Role>().Any())
{
context.Set<Role>().AddRange(
new Role { Name = "Admin" },
new Role { Name = "User" });
context.SaveChanges();
}
});
Плюс в том, что seed выполняется вместе с Migrate и dotnet ef database update, а EF защищает его механизмом блокировки миграций.
Если используете async-вариант, реализуйте и UseSeeding, и UseAsyncSeeding — EF tooling пока опирается на синхронный метод.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🔥1
Microsoft показала интеграцию .NET с Foundry Hosted Agents: существующий агент на Microsoft Agent Framework можно превратить в hosted agent практически без изменения логики.
dotnet add package Microsoft.Agents.AI.Foundry.Hosting --prerelease
var builder = AgentHost.CreateBuilder(args);
builder.Services.AddFoundryResponses(agent);
builder.RegisterProtocol(
"responses",
endpoints => endpoints.MapFoundryResponses());
azd provision
azd deploy
Foundry берёт на себя инфраструктуру, масштабирование, состояние сессий, identity, endpoint и observability. При этом сам AIAgent практически не меняется — вы просто добавляете вокруг него hosting-слой.
📍 Навигация: Вакансии • Задачи • Собесы
#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
🤩5🥱1