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

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

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

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

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Download Telegram
⚡️ Когда важна производительность

В C# цикл foreach часто воспринимается как самая удобная и красивая форма для обхода коллекций. Но в вопросах производительности foreach не всегда оптимален.

Почему лучше избегать foreach:

foreach использует итератор — для массивов его оптимизируют, но для списков, словарей и других коллекций создаётся объект или struct-итератор.

• под капотом foreach может создавать временные объекты, что увеличивает нагрузку на сборщик мусора и снижает производительность.

foreach всегда выполняет проверки и гарантирует корректность обхода, но это стоит некоторой производительности.

Что использовать вместо foreach:

Цикл for с индексом, особенно для массивов:
for (int i = 0; i < data.Length; i++)
{
// работа с data[i]
}


Span<T> и его методы — для обхода данных без выделения памяти и избыточных проверок:
var span = data.AsSpan();
for (int i = 0; i < span.Length; i++)
{
// работа с span[i]
}


Когда можно использовать foreach:

• Если цикл выполняется нечасто или количество элементов небольшое.

• Для обхода коллекций, где критичен чистый и понятный стиль программирования.

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔154🥱1
⭐️ Иммутабельность без танцев с бубном

Records — это ссылочный тип, который упростил жизнь разработчикам, привыкшим писать иммутабельные классы вручную. Вот зачем они нужны.

Раньше иммутабельный класс требовал много кода: readonly свойства, отключённые сеттеры, кастомные конструкторы. И всё равно где-то находилась лазейка. С Records это просто исчезает:
public record User(string Name, string Email);

var user = new User("Алексей", "alex@example.com");
// user.Name = "Новое имя"; — Ошибка компиляции


Все свойства автоматически получают init-accessor. Установить значение можно только при создании объекта. Это не просто синтаксический сахар — это гарантия от багов состояния, которые трудно найти.

Если вам нужен объект инициализатор, Records это поддерживают:
public record Product
{
public string Name { get; init; }
public decimal Price { get; init; }
}

var book = new Product { Name = "C# Deep Dive", Price = 49.99M };


Проще тестировать, проще рассуждать о коде, проще избежать багов в многопоточной среде. А ошибки, связанные с неожиданным изменением состояния, просто перестают существовать.

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🥱65
💻 Сравнение по значению автоматом

Вы знаете, что с классами сравнение — это боль? Два объекта с одинаковыми данными считаются разными, потому что сравнивается идентичность. Иначе работают Records:
public record Person(string FirstName, string LastName);

var p1 = new Person("Иван", "Иванов");
var p2 = new Person("Иван", "Иванов");

Console.WriteLine(p1 == p2); // true


Без переопределения Equals, без GetHashCode, без перегрузки оператора ==. Record сам сравнит все свойства и даст правильный результат.

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

var users = new HashSet<User>();
users.Add(new User("Мария", "maria@example.com"));
users.Contains(new User("Мария", "maria@example.com")); // true — работает!


Value-based семантика — это основа, на которой строятся остальные возможности Records.

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍181
📎 Копирование с with

Records поддерживают выражение with, которое создаёт изменённую копию объекта без изменения оригинала:
public record Person(string FirstName, string LastName);

var original = new Person("Анна", "Смирнова");
var updated = original with { LastName = "Петрова" };

Console.WriteLine(original.LastName); // Смирнова
Console.WriteLine(updated.LastName); // Петрова


Особенно полезно в event sourcing, CQRS или Redux-подобных архитектурах, где вы формируете новые состояния без мутации исходных данных:
public record Order(int Id, string Status);

var first = new Order(1, "Ожидает");
var second = first with { Status = "Обработан" };
var third = second with { Status = "Отправлен" };

// Все три состояния существуют независимо


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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
13👍11🥱4
👍 Распаковка данных в одну строку

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

Вместо того чтобы обращаться к каждому свойству отдельно:
public record Point(int X, int Y);

var point = new Point(15, 20);
int x = point.X;
int y = point.Y;


Просто распакуйте:
var (x, y) = new Point(15, 20);
Console.WriteLine($"Координаты: {x}, {y}");


Это особенно удобно в сочетании с pattern matching и switch выражениями:
public record User(string Name, int Age);

if (new User("Боб", 25) is { Age: > 18 })
Console.WriteLine("Взрослый пользователь");

var (name, age) = new User("Алиса", 30);


Вместо трёх строк получаете одну строку и респект от коллег не факт.

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
😢51👍1