Недавно мы делились новостью о выходе .NET 10 RC1. Теперь пришло время посмотреть глубже: что именно изменилось, какие улучшения можно опробовать уже сейчас.
Повышение производительности без усилий
• Улучшения в рантайме и JIT-компиляторе, благодаря которым уже существующий код работает быстрее при перекомпиляции, без изменения кода.
• «Deabstraction»: устранение накладных расходов за счёт оптимизации интерфейсов, лямбд, async, итераторов и др.
• Расширенный «escape analysis», позволяющее небольшие объекты размещать в стеке, а не на куче, что уменьшает нагрузку на garbage collector.
Улучшения рантайма и GC
• Поддержка AVX 10.2 инструкций — подготавливает платформу к современному железу.
• Оптимизация фонового GC, улучшение сжатия памяти и управления фрагментацией.
Безопасность и квантовая устойчивость
• Внедрение апи для пост-квантовой криптографии.
• Новый алгоритм цифровой подписи ML-DSA (основанный на решёточных структурах), стандартизированный NIST.
Новые возможности для разработчиков и приложений
• ASP.NET Core: более детальная телеметрия/метрики по аутентификации, токенам и двухфакторке, что облегчает выявление атак типа «credential stuffing», брут форс и др.
• EF Core: поддержка векторного поиска и нативного JSON в SQL Server — полезно для AI и полуструктурированных данных.
• .NET MAUI: метрики на уровне UI-layout операций (Measure, Arrange) — помогает обнаружить ботлнеки интерфейса.
C# 14 — язык становится дружелюбнее и эффективнее
• Возможность использовать params не только с массивами, но и со Span для уменьшения аллокаций.
• Новый field-контекст в свойствах упрощает код, убирает явное объявление «backing field» — меньше шаблонов, меньше шума.
Язык и среда .NET движутся в сторону объединения удобства и производительности: абстракции остаются, но их накладные расходы всё больше уходят.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25❤8⚡3🥰1
В .NET есть интерфейс
IReadOnlyList<T>. На первый взгляд, он обещает нам неизменяемый список. Но это полуправда.Определение интерфейса:
public interface IReadOnlyList<out T> : IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
T this[int index] { get; }
}
Интерфейс наследует IReadOnlyCollection, а тот, в свою очередь, наследует IEnumerable.
Таким образом, он даёт доступ: к элементам через индекс (this[int index]), к свойству Count, и к итерации через foreach.
⚠️ Важный нюанс: IReadOnlyList не делает коллекцию реально readonly.
Если у вас есть List<int> и вы приведёте его к IReadOnlyList<int>, изменять список по-прежнему можно — просто не через эту ссылку.
Пример:
var list = new List<int> { 1, 2, 3 };
IReadOnlyList<int> ro = list;
list.Add(4); // ro теперь "видит" 4То есть IReadOnlyList — это контракт для чтения, а не гарантия неизменности.
Если нужна настоящая защита — используйте ImmutableArray или ReadOnlyCollection.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🥱8❤🔥7👍1
В .NET-проектах часто пишут валидацию прямо в контроллере или сервисе:
— проверили, что поле не пустое,
— число больше нуля,
— email подходит по формату.
Это правильно, но есть проблема — бизнес-правила остаются размазаны по коду.
В итоге можно случайно создать объект в некорректном состоянии (например, заказ без товаров).
В идеале должно быть два уровня валидации Application Validation И Domain Validation. В одном проверяются входные данные, а в другом строится защита сущностей от нарушения бизнес-правил.
Пример проверки на уровне приложения:
public record CreateOrderDto(string CustomerEmail, List<OrderItemDto> Items);
public class OrderApplicationValidator
{
public static void Validate(CreateOrderDto dto)
{
if (string.IsNullOrWhiteSpace(dto.CustomerEmail))
throw new ArgumentException("Email is required");
if (!dto.CustomerEmail.Contains("@"))
throw new ArgumentException("Email format is invalid");
if (dto.Items == null || dto.Items.Count == 0)
throw new ArgumentException("Order must contain at least one item");
}
}
Здесь мы проверяем только корректность ввода.
А вот внутри домена мы защищаем бизнес-правила:
public class OrderItem
{
public string ProductName { get; }
public int Quantity { get; }
public Money Price { get; }
private OrderItem(string productName, int quantity, Money price)
{
ProductName = productName;
Quantity = quantity;
Price = price;
}
public static OrderItem Create(string productName, int quantity, Money price)
{
if (string.IsNullOrWhiteSpace(productName))
throw new InvalidOperationException("Product name cannot be empty");
if (quantity <= 0)
throw new InvalidOperationException("Quantity must be greater than zero");
return new OrderItem(productName, quantity, price);
}
public Money GetTotal() => Money.Create(Quantity * Price.Amount);
}
Когда правила закреплены в домене, они становятся частью самой логики, а не зависимыми от внешних слоёв. Это гарантирует, что объект в принципе невозможно построить в некорректном виде.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤1👍1
📀 Record-типы в C#
record в C# — это удобный способ описывать объекты данных без лишнего кода. Они сравниваются по значению, остаются неизменяемыми и отлично подходят для DTO или моделей в DDD.
Если раньше приходилось писать десятки строк с Equals, GetHashCode, ToString и конструкторами, то теперь всё это даёт одна строчка:
Отличие от классов
Class сравнивается по ссылке. Два объекта с одинаковыми данными — разные сущности.
Record сравнивается по значению. Два объекта с одинаковыми полями — эквивалентны.
Дополнительные фишки
Записи неизменяемы, но их удобно клонировать с изменением:
Можно наследовать record-тип:
record — это синтаксический сахар, который сокращает код и делает модели данных чище и понятнее.
🐸 Библиотека шарписта
#il_люминатор
record в C# — это удобный способ описывать объекты данных без лишнего кода. Они сравниваются по значению, остаются неизменяемыми и отлично подходят для DTO или моделей в DDD.
Если раньше приходилось писать десятки строк с Equals, GetHashCode, ToString и конструкторами, то теперь всё это даёт одна строчка:
public record User(string Name, int Age);
Отличие от классов
Class сравнивается по ссылке. Два объекта с одинаковыми данными — разные сущности.
Record сравнивается по значению. Два объекта с одинаковыми полями — эквивалентны.
var u1 = new User("Alice", 25);
var u2 = new User("Alice", 25);
Console.WriteLine(u1 == u2); // trueДополнительные фишки
Записи неизменяемы, но их удобно клонировать с изменением:
var u1 = new User("Alice", 25);
var u2 = u1 with { Age = 26 };
Console.WriteLine(u2); // User { Name = Alice, Age = 26 }Можно наследовать record-тип:
public record User(string Name, int Age);
public record Admin(string Name, int Age, string Role) : User(Name, Age);
record — это синтаксический сахар, который сокращает код и делает модели данных чище и понятнее.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24❤1
Когда вы пишете асинхронный метод вроде:
async Task<int> GetDataAsync()
{
var data = await FetchAsync();
return data.Length;
}
вы можете думать, что это «всего лишь ожидание задачи». Но на самом деле компилятор C# превращает этот метод в state machine — конечный автомат, который управляет переходами между состояниями выполнения.
State machine — это структура, которая:
• хранит текущее состояние выполнения программы, например, до await, после await или завершено,
• знает, в какое состояние перейти дальше, когда наступает внешнее событие например, завершение Task.
Проще говоря, компилятор разворачивает ваш линейный асинхронный код в набор состояний + переключатель между ними.
Что делает компилятор
При компиляции метода с await создаётся вспомогательный класс, реализующий интерфейс
IAsyncStateMachine.Если упростить, то наш пример превращается примерно в:
private struct GetDataAsyncStateMachine : IAsyncStateMachine
{
public int _state;
public AsyncTaskMethodBuilder<int> _builder;
private TaskAwaiter<string> _awaiter;
public void MoveNext()
{
try
{
if (_state == 0)
{
// после await
var result = _awaiter.GetResult();
_builder.SetResult(result.Length);
return;
}
var task = FetchAsync();
if (!task.IsCompleted)
{
_state = 0;
_awaiter = task.GetAwaiter();
_builder.AwaitUnsafeOnCompleted(ref _awaiter, ref this);
return;
}
_builder.SetResult(task.Result.Length);
}
catch (Exception ex)
{
_builder.SetException(ex);
}
}
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
}
Другие примеры использования state machines в C#
• yield return — генерация итераторов
IEnumerator• foreach на async коллекциях — асинхронные итераторы
IAsyncEnumerableКаждый await или yield превращает метод в "автомат", который сам управляет своим ходом выполнения.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🥱7❤5
🚀 JetBrains .NET Days 2025
JetBrains снова собрала лучших инженеров и евангелистов .NET на своей онлайн-конференции .NET Days. Два дня плотных докладов — от чистой архитектуры и распределённых систем до GenAI и F#.
1️⃣ Самое интересное за первый день:
• Чистая архитектура с ASP.NET Core
Как выстроить проект так, чтобы код был читаемым, тестируемым и легко рефакторился. Разделение слоёв и зависимостей без боли.
• Nullability в C#: включаем защиту от NullReferenceException
Аннотации и статический анализ помогают избавиться от NullReferenceException и внедрить null safety даже в старый код.
• Как выбрать систему обмена сообщениями
Сравнение AWS SQS, RabbitMQ и Azure Service Bus — плюсы, минусы и типичные ошибки при выборе очередей сообщений.
• TDD на фронтенде с Blazor
Как применять TDD на фронтенде с Blazor и bUnit. Быстрая обратная связь и уверенность в каждом изменении.
2️⃣ Темы за второй день:
• Версионирование событийных систем
Безопасные приёмы эволюции событий: версионирование, апкастинг и совместимость без поломок у потребителей.
• Генеративный ИИ и .NET Aspire в действии
Интеграция LLM, управление контекстом и масштабируемая оркестрация с помощью Semantic Kernel и Aspire.
• Функциональное программирование в F#: мода или польза
Реальные преимущества функционального подхода — лаконичные пайплайны, паттерн-матчинг и безопасные абстракции.
• Как нашли утечку 2 ГБ в день за 5 минут
История о том, как обнаружить гигабайтные утечки памяти с помощью dotMemory в продакшене за считанные минуты.
Два дня — и десятки инсайтов о будущем .NET: от облаков и AI до функционального подхода и устойчивой архитектуры. Записи доступны на YouTube.
➡️ Первый день
➡️ Второй день
🐸 Библиотека шарписта
#il_люминатор
JetBrains снова собрала лучших инженеров и евангелистов .NET на своей онлайн-конференции .NET Days. Два дня плотных докладов — от чистой архитектуры и распределённых систем до GenAI и F#.
• Чистая архитектура с ASP.NET Core
Как выстроить проект так, чтобы код был читаемым, тестируемым и легко рефакторился. Разделение слоёв и зависимостей без боли.
• Nullability в C#: включаем защиту от NullReferenceException
Аннотации и статический анализ помогают избавиться от NullReferenceException и внедрить null safety даже в старый код.
• Как выбрать систему обмена сообщениями
Сравнение AWS SQS, RabbitMQ и Azure Service Bus — плюсы, минусы и типичные ошибки при выборе очередей сообщений.
• TDD на фронтенде с Blazor
Как применять TDD на фронтенде с Blazor и bUnit. Быстрая обратная связь и уверенность в каждом изменении.
• Версионирование событийных систем
Безопасные приёмы эволюции событий: версионирование, апкастинг и совместимость без поломок у потребителей.
• Генеративный ИИ и .NET Aspire в действии
Интеграция LLM, управление контекстом и масштабируемая оркестрация с помощью Semantic Kernel и Aspire.
• Функциональное программирование в F#: мода или польза
Реальные преимущества функционального подхода — лаконичные пайплайны, паттерн-матчинг и безопасные абстракции.
• Как нашли утечку 2 ГБ в день за 5 минут
История о том, как обнаружить гигабайтные утечки памяти с помощью dotMemory в продакшене за считанные минуты.
Два дня — и десятки инсайтов о будущем .NET: от облаков и AI до функционального подхода и устойчивой архитектуры. Записи доступны на YouTube.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🔥4👍3
В C# каждое обращение к элементу массива проверяется на выход за границы. Это безопасно, но медленно. Разработчики часто решают проблему через unsafe-код с указателями — быстро, но опасно: один неверный индекс, и приложение крашится или получает дыру в безопасности.
Есть третий путь —
Span<T>Span — это структура, которая хранит указатель на данные и их длину. Фишка в том, что это ref struct — она живёт только в стеке и не может попасть в кучу. Благодаря этому компилятор гарантирует: данные переживут span, а значит проверки границ можно убрать.
Например, в быстрой сортровке вместо передачи массива с индексами low/high передаёте span. Код короче, переполнение невозможно, а рекурсивные вызовы работают через срезы:
// Было: опасно, (low + high) может переполниться
void Quicksort(int[] array, int low, int high) {
int mid = (low + high) / 2; // 💥 overflow!
// ...
Quicksort(array, low, pivot - 1);
Quicksort(array, pivot + 1, high);
}
// Стало: безопасно и выразительно
void Quicksort(Span<int> span) {
if (span.Length <= 1) return;
int pivot = Partition(span);
Quicksort(span[..pivot]); // левая часть
Quicksort(span[(pivot + 1)..]); // правая часть
}
Раньше для передачи части массива в функцию приходилось либо копировать данные, либо таскать массив + offset + length. Span решает это элегантно: создаёте срез array[10..20], передаёте дальше — никакого копирования, полная безопасность типов.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17⚡1❤1😁1
List<T> — это универсальный солдат C#. Но универсальный не значит оптимальный. Пока вы перебираете 10 000 элементов через .FirstOrDefault(), Dictionary находит нужное за одно обращение. И это только начало.Queue — когда порядок имеет значение
Обрабатываете задачи по очереди? Вот вам готовое решение:
var tasks = new Queue<UserRequest>();
tasks.Enqueue(new UserRequest { Id = 1, Name = "Alice" });
tasks.Enqueue(new UserRequest { Id = 2, Name = "Bob" });
// Безопасное извлечение (с .NET 6+)
while (tasks.TryDequeue(out var request))
{
await ProcessAsync(request);
}
Первым пришел — первым обработался. Никаких индексов, никаких сортировок.
Stack — для истории действий
Делаете undo/redo или навигацию? Стек решает это из коробки:
var history = new Stack<string>();
history.Push("/home");
history.Push("/products");
history.Push("/cart");
// Вернуться назад
if (history.TryPop(out var lastPage))
{
Console.WriteLine($"Back to: {lastPage}"); // /cart
}
Последнее действие всегда доступно первым. Логика браузерной кнопки «Hазад» готова.
Dictionary — когда нужна скорость
Поиск по ключу за O(1) вместо перебора всего списка:
var users = new Dictionary<int, User>();
users.Add(1, new User { Name = "Alice" });
users.Add(2, new User { Name = "Bob" });
// Безопасная проверка
if (users.TryGetValue(2, out var user))
{
Console.WriteLine(user.Name); // Bob
}
Никаких .FirstOrDefault(x => x.Id == 2) с перебором тысяч записей.
List отлично работает, когда вам нужен доступ по индексу и порядок элементов. Но если задача укладывается в одну из этих трёх структур — используйте их.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱24❤10
Представьте, что вы отправили друга в магазин с деньгами на общий счёт. Он может потратить их на что угодно, при этом никому не отчитываясь. Вот примерно так же работает
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
В C# 14 расширяется концепция расширений: можно создавать не только расширенные методы для экземпляров типов, но и свойства расширения, а также расширения, которые относятся к самому типу как к статическому элементу.
Пример:
public static class EnumerableExtensions
{
extension<TSource>(IEnumerable<TSource> source)
{
public bool IsEmpty => !source.Any(); // Расширенное свойство
}
extension<TSource>(IEnumerable<TSource>)
{
public static IEnumerable<TSource> Combine(IEnumerable<TSource> first, IEnumerable<TSource> second)
=> first.Concat(second); // Статический метод расширения
}
}
Конструкция
extension<TSource>(IEnumerable<TSource> source) — это новый синтаксис блока расширения для экземпляра типа: здесь определяются расширяющие члены, которые «прикрепляются» к объекту IEnumerable<TSource>.Внутри блока объявлено свойство
IsEmpty, которое возвращает true, если последовательность пуста (!source.Any()).Второй блок
extension<TSource>(IEnumerable<TSource>) — расширение для самого типа IEnumerable<TSource> как статического члена.Внутри него определён статический метод Combine, который принимает две последовательности и объединяет их с помощью Concat.
Как это использовать:
var list = new List<int> { 1, 2, 3 };
bool empty = list.IsEmpty; // false — вызов расширенного свойства как у экземпляра
var combined = Enumerable<int>.Combine(new[] { 1 }, new[] { 2, 3 }); // {1, 2, 3}#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥5❤3😁3
Управление данными в свойствах теперь проще с новым ключевым словом для доступа к автоматически созданному полю.
Раньше для добавления логики установки значения использовалось отдельное поле и аксессоры:
private string _msg;
public string Message
{
get => _msg;
set => _msg = value ?? throw new ArgumentNullException(nameof(value));
}
Сейчас field ссылается на поле, которое создает компилятор, сокращая код:
public string Message
{
get;
set => field = value ?? throw new ArgumentNullException(nameof(value));
}
Минимум кода — максимум контроля: write-only свойства снаружи и строгая логика внутри.
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21❤2😁2
🛠 Натуральные преобразования для Span и ReadOnlySpan
C# 14 позволяет неявно преобразовывать между
Типы
🐸 Библиотека шарписта
#il_люминатор
C# 14 позволяет неявно преобразовывать между
Span<T>, ReadOnlySpan<T> и массивами, упрощая манипуляции с данными и повышая скорость:ReadOnlySpan<char> roSpan = "hello";
Span<char> span = roSpan;
char[] array = roSpan.ToArray();
Типы
Span теперь могут выступать как принимающие методы расширения, то есть станут получателями вызова таких методов. Они также могут комбинироваться с другими типами преобразований.#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤2⚡1
Вы пишете библиотеку на C#, используете async/await, и всё работает. Но потом ваша библиотека попадает в веб-приложение, мобильное приложение, или какой-то другой контекст — и начинаются странные deadlock'и или даже зависания.
Проблема вот в чём: когда код выходит из await, он хочет продолжить выполнение в том же контексте, в котором был запущен. Если это UI-приложение, контекст одноточечный — только главный поток может работать с UI.
Если ваша библиотека захватит этот контекст и не отпустит — приложение зависнет. А если написали синхронный код, который вызывает async библиотеку, и она захватит контекст — будет deadlock.
ConfigureAwait(false) как раз говорит: «Мне вообще всё равно, в каком контексте продолжать. Возьми любой поток из thread pool'а«. И вот это спасает приложения от проблем:await stream.WriteAsync(buffer, ct).ConfigureAwait(false);
Результат: библиотека не блокирует контекст, не создаёт deadlock'и, работает везде одинаково.
Когда НЕ нужен ConfigureAwait(false):
В приложениях можно писать без него, если вам нужен контекст:
// В ASP.NET контроллере — можно без ConfigureAwait(false)
[HttpGet]
public async Task<IActionResult> GetData()
{
var data = await service.GetDataAsync(); // Контекст нужен для логирования, etc
return Ok(data);
}
// В UI приложении — нужен контекст
private async void Button_Click(object sender, EventArgs e)
{
var data = await LoadDataAsync(); // Нужно вернуться в UI поток
UpdateUI(data);
}
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍11🥱1
🧑💻 Контролируем параллельную работу
Представьте ситуацию: у вас есть 1000 элементов для обработки, и вы хотите запустить это параллельно. Но если просто запустить все одновременно, приложение упадёт — будет слишком много одновременных подключений к БД, API или файловой системе.
Здесь помогает
Как это работает
Создаём семафор с лимитом 4. Это значит, что максимум 4 потока могут находиться внутри защищённого блока одновременно.
Поток ждёт в очереди, пока не появится "место". Если уже 4 потока внутри — новичок подождёт:
После обработки обязательно вызываем
Вместо 100 одновременных загрузок будет ровно столько, сколько вы укажете.
🔹 Алгоритмы и структуры данных
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸 Библиотека шарписта
#il_люминатор
Представьте ситуацию: у вас есть 1000 элементов для обработки, и вы хотите запустить это параллельно. Но если просто запустить все одновременно, приложение упадёт — будет слишком много одновременных подключений к БД, API или файловой системе.
Здесь помогает
SemaphoreSlim. Как это работает
Создаём семафор с лимитом 4. Это значит, что максимум 4 потока могут находиться внутри защищённого блока одновременно.
await gate.WaitAsync(ct);
Поток ждёт в очереди, пока не появится "место". Если уже 4 потока внутри — новичок подождёт:
await gate.WaitAsync(ct);
После обработки обязательно вызываем
Release() — это освобождает место для следующего потока. finally гарантирует, что это произойдёт даже если операция упадёт:try { await Process(x, ct); }
finally { gate.Release(); }Вместо 100 одновременных загрузок будет ровно столько, сколько вы укажете.
🔹 Алгоритмы и структуры данных
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Новый уровень модульности в больших проектах: делим объявление и реализацию. Большие проекты требуют таких гибких способов организации кода.
В C# теперь можно объявлять события и конструкторы с модификатором partial. Это значит, что объявление может находиться в одном месте, а его реализация — в другом, обычно в другом файле:
public partial class MyClass
{
partial void OnInitialized();
public MyClass()
{
OnInitialized();
}
}
Здесь объявлена частичная функция
OnInitialized() без тела — её реализация может появиться отдельно. Также конструктор вызывает эту функцию, если она реализована.Частичные конструкторы поддерживают совместимость с платформами, использующими генерацию кода.
🔹 Практический интенсив «Архитектуры и шаблоны проектирования»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔5❤2🥱1
Представьте фоновую задачу, которая должна срабатывать каждые 5 секунд: проверка очереди, синхронизация данных, отправка метрик. Можно, конечно, использовать
Task.Delay, но это хрупко — если одна итерация длится дольше, чем ожидалось, ритм собьётся.PeriodicTimer решает эту проблему иначе:var timer = new PeriodicTimer(TimeSpan.FromSeconds(5));
Создаём таймер, который будет срабатывать каждые 5 секунд. Точка отсчёта — момент создания.
while (await timer.WaitForNextTickAsync(ct))
{
await DoWork(ct);
}
WaitForNextTickAsync ждёт следующего тика таймера. Когда он приходит — выполняем работу. Если работа заняла 1 секунду, следующий тик всё равно придёт через 5 секунд от начала цикла, а не через 6.Это стабильный интервал, а не интервал между завершением одной работы и началом другой.
🔹 Практический интенсив «Архитектуры и шаблоны проектирования»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍8
🛠 Как создать путь к временному файлу в C#
В C# для работы с путями к файлам существует класс
Другой полезный метод —
Пример:
Использование
🔸 Основы IT для непрограммистов
🔸 Получить консультацию менеджера
🔸 Сайт Академии 🔸 Сайт Proglib
🐸 Библиотека шарписта
#il_люминатор
В C# для работы с путями к файлам существует класс
Path, который предлагает методы для объединения частей путей и получения системных директорий. Один из таких методов — GetTempPath(). Он возвращает путь к папке, предназначенной для временных файлов на текущей системе.Другой полезный метод —
Combine(). Он соединяет несколько частей пути, учитывая особенности слэшей в Windows, Linux и macOS. Вместо ручного склеивания строк и риска ошибок, Combine() гарантирует правильный формат.Пример:
using System;
using System.IO;
class Program
{
static void Main()
{
// Получаем путь к системной временной папке и добавляем имя файла
var path = Path.Combine(Path.GetTempPath(), "report.csv");
Console.WriteLine("Путь к временному файлу: " + path);
// Здесь можно сохранить файл, открыть или выполнить другие операции
}
}
Использование
Path.GetTempPath() и Path.Combine() — простой способ получить корректный путь к временному файлу без ошибок и с учётом особенностей операционных систем. 🔸 Основы IT для непрограммистов
🔸 Получить консультацию менеджера
🔸 Сайт Академии 🔸 Сайт Proglib
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23🥱7