.NET Разработчик
6.51K subscribers
427 photos
2 videos
14 files
2.04K links
Дневник сертифицированного .NET разработчика.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1829. #Карьера
Когда Начальник Вас не Слушает

В идеале руководитель должен вдохновлять и поддерживать вас, назначать вам проекты и направлять вас к росту и устранять любые препятствия. Обычно не всё так гладко. Многие сотрудники жалуются, что их менеджеры «просто не слушают»: от явного игнорирования при предоставлении обратной связи до упущения продвижения по службе. Рассмотрим как мы можем каждый раз достигать наилучшего результата в разных сценариях.

1. Начальник не слушает отзывы
Возможно, будет полезно обсудить проблему с остальной командой. Это типично для всех или направлено конкретно против вас? Убедитесь, что ваш руководитель понимает ваши отзывы, сделав их прямыми, конкретными и своевременными. Изучите, как вы выражаете эту обратную связь, поскольку ваши стили общения могут противоречить. Во время встреч обращайте внимание на то, как с ним разговаривают другие люди, и поймите, какой стиль общения привлекает внимание вашего начальника.

2. Начальник игнорирует мои идеи
Упорно работать над чем-то может показаться деморализующим, если начальство игнорирует ваш вклад и выбирает совершенно другое направление.
В таких случаях может помочь переоценка вашей презентации. Постарайтесь найти наиболее важную часть вашей идеи и договориться о ней, вместо того чтобы настаивать на полном пакете.
Сосредоточьтесь на чём-то, что принесет ощутимые результаты для бизнеса либо напрямую (за счет зарабатывания денег), либо косвенно (например, за счет снижения затрат или повышения эффективности). Если возможно, создайте доказательство концепции и измерьте результат. Представьте эти результаты руководителю.

3. Начальник не помогает с проблемами по работе
Всего 23% сотрудников сообщают, что их руководитель всегда конструктивно реагирует, когда они делятся своими рабочими проблемами, а 17% утверждают, что их руководитель вообще им не помогает.
Постарайтесь разобраться в проблеме. Может у него много дел, и нет времени вам помочь. Тогда предложите свою помощь в каких-то вопросах.
Ещё одна причина, может быть в том, что начальник хочет, чтобы вы сами нашли решение и получили опыт. Если вы исчерпали все возможные варианты и не знаете, как двигаться дальше, важно подчеркнуть это.

4. Начальник игнорирует мой запрос на повышение
Во-первых, вы просили или просто намекнули об этом? Если явно просили, попробуйте узнать, это осознанное и окончательное решение, проблема с бюджетом или местом в текущей команде? Если не хватает бюджета, спросите, есть ли график продвижений и что нужно сделать, чтобы получить повышение, и когда на него рассчитывать?

Поднимите проблему
Не уклоняйтесь от обсуждения проблем и не позволяйте проблеме накапливаться. Относитесь к этому так же, как к любой обратной связи; давайте её своевременно и привяжите к конкретным фактам. Какое именно поведение начальства заставило вас почувствовать, что вас игнорируют? Соблазнительно начать жаловаться, но полезнее переключиться в режим решения проблем. Подумайте, как вы можете быть наиболее полезны для бизнеса.

Говорить ли с начальством начальства?
Иногда может возникнуть соблазн переступить через голову. Прежде чем делать это, учтите последствия. Это необратимо повлияет на ваши отношения. Даже если вы добьётесь своего, после этого вашему руководителю будет трудно вам доверять. В некоторых компаниях начальник вашего руководителя наотрез откажется с вами разговаривать, вам могут сделать выговор или даже уволить. Это можно делать, только если произойдёт что-то неэтичное или незаконное.

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

Источник: https://betterprogramming.pub/when-your-manager-does-not-listen-55875a35c974
👍10👎2
День 1830. #ЗаметкиНаПолях
Проверяем, Пустая ли Коллекция в C#
В C# существуют разные способы проверить, пустая ли коллекция. В зависимости от типа коллекции вы можете проверить свойства Length, Count или IsEmpty. Также можно использовать метод расширения Enumerable.Any().
// массив: Length
int[] array = ...;
var isEmpty = array.Length == 0;

// List: Count
List<int> list = ...;
var isEmpty = list.Count == 0;

// ImmutableArray<T>: IsEmpty
ImmutableArray<int> immArray = ...;
var isEmpty = immArray.IsEmpty;

// Span: IsEmpty
Span<int> span = ...;
var isEmpty = span.IsEmpty;

// метод расширения
List<int> list = ...;
var isEmpty = !list.Any();


В C# 11, вы можете использовать сопоставление с образцом, чтобы позволить компилятору использовать лучший метод для проверки того, пуста ли коллекция. Не нужно запоминать правильное имя свойства, можно использовать оператор is:
var collection = ...;
var isEmpty = collection is [];


Обратите внимание, что предыдущий код не совсем эквивалентен проверке свойства Length. Если экземпляру коллекции присвоить NULL, проверка свойства вызывает исключение NullReferenceException, а сопоставление с образцом вернёт false:
int[] array = null;
// NullReferenceException
var isEmpty = array.Length == 0;
// false
var isEmpty = array is [];


Проверить на null и пустую коллекцию, можно так:
var isNullOrEmpty = array is null or [];


Ту же логику можно использовать и для строк, хотя использование string.IsNullOrEmpty гораздо более распространено:
string str = "";
isEmpty = str is "";
isEmpty = str is [];


Источник: https://www.meziantou.net/checking-if-a-collection-is-empty-in-csharp.htm
👍37
День 1831. #ЧтоНовенького #CSharp13
Три новых метода LINQ в .NET 9

Продолжаем заглядывать в будущее .NET. Сегодня посмотрим, какие новые методы будут добавлены во всеми любимый LINQ.

CountBy
Многие функции LINQ имеют расширение By, в котором можно предоставить функцию выбора для группировки элементов. Например, MinBy, MaxBy, DistinctBy и т. д. Теперь у нас есть новый: CountBy. Он группирует элементы по функции селектора и возвращает перечисление KeyValuePairs. Ключ — это объект, а значение — количество элементов в группе.
public record Person(string FirstName, string LastName);

List<Person> people =
[
new("Steve", "Jobs"),
new("Steve", "Carell"),
new("Elon", "Musk")
];

foreach (var p in people.CountBy(p => p.FirstName))
Console.WriteLine($"{p.Value} людей с именем {p.Key}");

Вывод:
2 людей с именем Steve
1 людей с именем Elon


Index
Не то, чтоб совсем новинка, это можно делать и сейчас, но с другим синтаксисом. Index возвращает элемент и его индекс в коллекции:
foreach (var (index, item) in people.Index())
Console.WriteLine($"№{index}: {item}");


Сейчас такого можно добиться, используя перегрузку метода Select:
foreach (var (item, index) in 
people.Select((item, index) => (item, index)))
{
Console.WriteLine($"№{index}: {item}");
}

Интересно, что в методе Index решили поменять порядок индекса и элемента. Оказывается, это было осознанным решением команды дотнет: «Мы решили сначала возвращать индекс, а затем значение, потому что это кажется более естественным, несмотря на то, что существующий метод Select() сначала возвращает значение, а потом индекс.»

AggregateBy
Этот метод похож на CountBy, но вместо подсчёта элементов он их агрегирует. Вы можете предоставить начальное значение и функцию агрегирования. Функция получает текущее агрегированное значение и текущий элемент в качестве параметров и должна вернуть новое агрегированное значение.
public record Person(
string FirstName,
string Department,
int Salary);

List<Person> people =
[
new("Jobs", "Sales", 100),
new("Carell", "Sales", 120),
new("Musk", "IT", 290)
];

var aggregateBy = people.AggregateBy(
p => p.Department,
x => 0,
(x, y) => x + y.Salary
);
foreach (var kvp in aggregateBy)
Console.WriteLine($"ФОТ отдела {kvp.Key}: {kvp.Value}");

Вывод:
ФОТ отдела Sales: 220
ФОТ отдела IT: 290


Источник: https://steven-giesel.com/blogPost/0594ba85-356b-47f1-89a9-70e9761c582e/three-new-linq-methods-in-net-9
👍25
День 1832. #ЗаметкиНаПолях
.http-Файл в Visual Studio не Отправляет Заголовок Авторизации
При отправке запросов к API в Visual Studio возникает странная проблема. Bearer-токен, который в Swagger работает нормально, в файле .http просто игнорируется, что приводит к ошибке 401 Unauthorized.

Проблема
Простой проект Webapi ASP.NET Core, используя шаблон по умолчанию со встроенной поддержкой .http-файлов для выполнения запросов к проекту. Регистрация и вход в систему работают нормально, но попытка доступа к конечной точке, требующей аутентификации, всегда приводит к ошибке 401. Тот же токен, добавленный в тот же заголовок авторизации, отлично работает при использовании Swagger/Swashbuckle в браузере.

Диагностика проблемы
На вкладке Request info (Информация о запросе) в файле .http даже не отображался заголовок Authorization (но отображался кастомный заголовок Authorization2, который был идентичен во всех отношениях, кроме имени). Стало ясно, что это было так и задумано. Проблема в том, что запрос из .http-файла первоначально отправлялся на https://localhost:5206/cart, который перенаправлялся на https://localhost:7248/cart из-за использования промежуточного ПО UseHttpsRedirection.

Конечная точка http была настроена как переменная в верхней части файла .http, поэтому даже в самом файле не было очевидно, что данный запрос использует не тот URL/порт:
POST {{BaseUrl}}/cart


На вкладке Request (Запрос) вывода .http-файла отображался URL https://localhost:7248/cart, что никак не обозначает, что он неправильный (не тот, куда шёл изначальный запрос). Единственная проблема – отсутствие заголовка авторизации.

Возможно, было бы неплохо включить на вкладке Request (или где-то еще) информацию о том, что было выполнено перенаправление и что конечный URL не соответствует исходному запрошенному URL.

Заголовки перенаправления и авторизация
Основная проблема тут в том, как работает UseHttpsRedirection. Он отправляет клиенту в ответ заголовок перенаправления, и если клиент настроен на автоматическое следование перенаправлениям, он «молча» переходит на предложенный в перенаправлении URL. Однако также существует соглашение не пересылать заголовки авторизации при перенаправлениях:
«Заголовок Authorization очищается при автоматическом перенаправлении, и обработчик автоматически пытается повторно пройти аутентификацию на целевом URL. Никакие другие заголовки не очищаются. На практике это означает, что приложение не может помещать пользовательскую информацию аутентификации в заголовок Authorization, если есть возможность столкнуться с перенаправлением. Вместо этого приложение должно реализовать и зарегистрировать собственный модуль аутентификации.»

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

Посмотрите предложение об изменении поведения файлов .http в Visual Studio и проголосуйте, если заинтересует.

Итого
Надеюсь, изложенное выше поможет сэкономить кому-то время. Если вы получаете ошибку 401 Unauthorized, даже если вы правильно настроили заголовок авторизации, и заметили, что заголовок авторизации отсутствует, ищите виновника в перенаправлении. Это может быть неочевидно в ваших инструментах, особенно если всё настроено на автоматическое следование перенаправлениям.

Источник: https://ardalis.com/http-file-not-sending-auth-header/
👍17
День 1833. #ЗаметкиНаПолях
Обзор Инструментов Покрытия Кода для C#. Начало
В этой серии постов рассмотрим различные инструменты покрытия кода в .NET и перечислим их функции.

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

Что это и зачем?
Если коротко, измерения покрытия кода показывают, какие строки кода ваш набор тестов выполняет, а какие нет. Простой пример:
public int Divide(int x, int y)
{
if(y != 0)
return x / y;

return 0;
}

Допустим, это единственный метод в нашей кодовой базе, и мы написали один модульный тест, что Divide(2, 1) должно вернуть 2. Мы получим 67% покрытия кода, т.к. тест заставит среду проверить условие, и вернуть x/y, таким образом выполнив 2 строки метода из 3х.

Разработчики могут использовать анализ покрытия кода, чтобы увидеть дыры в своём тестировании. В примере выше анализ покрытия кода подскажет, что надо протестировать случай, когда y=0.

Инструменты
Практически в любом языке и технологическом стеке есть способы определить, насколько полно набор модульных тестов покрывает вашу кодовую базу. Однако не путайте покрытие кода с оценкой качества ваших тестов. Это просто мера объёма кода, проверяемого тестами. Следующие инструменты помогут вам оценить покрытие кода тестами в .NET.

1. Visual Studio Code Coverage
Если у вас корпоративная версия Visual Studio, вы можете воспользоваться этой возможностью «из коробки». Более подробно об этом можно прочитать на сайте документации Microsoft. Но это хороший, комплексный вариант, который требует совсем немного дополнительной работы, при условии, что у вас есть правильная версия. И у него есть интересные функции:
- Сообщает процент покрытия с различной степенью детализации (например, сборка, класс и т. д.).
- Вы можете выбрать все тесты или их подмножество.
- Подсветка кода в IDE, т.е. он показывает, какие строки кода покрыты тестами, когда вы смотрите на код.
- Продукт Microsoft, поэтому вы можете рассчитывать на обновления и поддержку.

2. dotCover в Rider и ReSharper
Если у вас есть лицензия Visual Studio Enterprise, ваша жизнь во многих отношениях хороша. Если нет, выкладывать $3000 в год только ради покрытия кода, наверное, перебор.
Другой вариант - JetBrains dotCover, который входит в предложения Jetbrains (от $349 до $779 в год). Вы получите анализ покрытия, а также Rider и ReSharper, которые являются действительно классными инструментами.
Некоторые основные функции dotCover:
- Подробная отчётность.
- Исполнители тестов. Тесты также можно запускать с помощью профилировщика dotTrace для измерения производительности.
- Интеграция измерений покрытия как в Visual Studio, так и в CI.
- Переход к покрывающим тестам.
- Хороший обзор «горячих точек», показывающий рискованные методы.
- Отрисовка зеленых/красных операторов в IDE.

Окончание следует…

Источник:
https://blog.ndepend.com/guide-code-coverage-tools/
👍1
День 1834. #ЗаметкиНаПолях
Обзор Инструментов Покрытия Кода для C#. Окончание

Начало

3. NCrunch
Предоставит вам данные о покрытии кода, а также подсветит покрытый и непокрытый тестами код в IDE. Кроме этого, NCrunch постоянно запускает ваши тесты в режиме реального времени по мере того, как вы печатаете. Это живое модульное тестирование. С NCrunch вам не нужно запускать тесты или даже компилировать код, чтобы получить информацию о том, нарушают ли что-нибудь ваши изменения в коде. Отметки о покрытии будут меняться по мере ввода.
Другие особенности:
- Небольшой и настраиваемый объем используемой памяти.
- Встроенные сведения об исключениях и простая отладка, интегрированная в VS.
- Безопасное многопроцессное параллельное выполнение тестов с возможностью масштабирования.
- Пассивный сбор данных как о покрытии кода, так и о производительности.
- Интеллектуальное выполнение, способное исполнять только те тесты, на которые влияют изменения.
- Очень быстрое выполнение тестов и возможность работать с очень большими наборами тестов.
Цены на NCrunch очень разумные: от $159 до $289 за лицензию для отдельного разработчика.

4. AltCover (ранее известный как OpenCover)
Вот уже несколько лет бесплатный инструмент с открытым кодом AltCover, разработанный на F# Стивом Гилхэмом, заменил известный инструмент OpenCover.
Особенности:
- Инструмент командной строки, предназначенный для сбора информации о покрытии кода .NET. Поддерживаются среды выполнения .NET Core, .NET Framework и Mono.
- Легко интегрируется с задачами MSBuild, предлагая надёжную поддержку для управления инструментом, включая полную интеграцию с функциями dotnet test.
- Предоставляет универсальный расширяемый API, который легко интегрируется с популярными инструментами автоматизации сборки, такими как Fake и Cake.
- Расширяет совместимость со средами PowerShell, предлагая специальный модуль, совместимый как с PowerShell 5.1, так и с PowerShell Core 6+.
- Включает специализированный инструмент визуализации покрытия, основанный на AvaloniaUI.

5. Coverlet
Coverlet — фреймворк покрытия кода, разработанный для .NET и предлагающий поддержку покрытия строк, ветвей и методов. Он совместим с .NET Framework и .NET Core на всех поддерживаемых платформах.
Особенности:
- Легкая интеграция в проекты .NET, не создавая при этом большой нагрузки на систему.
- Бесплатный и с открытым исходным кодом.
- Гибкая конфигурация в соответствии с конкретными требованиями и предпочтениями по покрытию кода.
- Предоставляет надёжную и подробную информацию о коде, помогая выявить области, требующие тестирования и улучшения.
Если вы используете Visual Studio Code, Coverlet станет отличным инструментом.

6. Fine Code Coverage
Бесплатное расширение Visual Studio, предназначенное для предоставления данных о покрытии в IDE. Оно работает со всеми выпусками Visual Studio, включая версию Community. Fine Code Coverage добавляет специальное окно в VS, в котором есть вкладки, предоставляющие ценную информацию о степени покрытия кода с разбитием на проекты и классы, а также подсветку покрытых строк кода.

Источник: https://blog.ndepend.com/guide-code-coverage-tools/
👍12👎1
День 1835. #ЗаметкиНаПолях
Пять Шагов по Управлению Легаси-Кодом. Начало
Работать с легаси-кодом не особо весело, но это неизбежно. Разработчик вы, технический руководитель или менеджер продукта, наступит момент, когда какая-то работа, которую вы хотите выполнить, будет связана с устаревшим кодом. Рассмотрим, что на самом деле означает устаревший код и как продумать возможные решения для улучшения состояния кодовой базы и способностей вашей команды эффективно поставлять функции.

1. Принятие существования легаси-кода
Прежде чем приступить к работе с устаревшим кодом, признать, что все кодовые базы и все команды будут иметь код, который они определяют как «устаревший». И это не вина ни команды, ни конкретного разработчика. Существуют методы поддержки низкого уровня легаси-кода и активного его сокращения, но искоренить весь устаревший код — это неправильная, нереалистичная цель, которая, вероятно, контрпродуктивна для бизнеса и его потребностей.

2. Реалистичный подход к определению легаси-кода
Термин «устаревший код» часто используется, и для команды важно иметь чёткое определение, которое разделяет и понимает каждый. Старый код не обязательно является легаси-кодом. Понятие легаси-кода связано не столько с его возрастом, сколько с характеристиками, которые делают работу над ним сложной и непродуктивной, например:
- Отсутствие автоматизированных тестов. Когда разработчики вносят изменения в этот код, им приходится тестировать его вручную, поскольку не существует автоматического покрытия ни на каком уровне (модульные тесты, интеграционные тесты, сквозные тесты и т. д.).
- Отсутствие документации. Когда разработчикам приходится работать с этим кодом, им сложно его понять. Это может быть связано с тем, что код написан так, что его функциональность становится нечёткой, но на это также влияет отсутствие документации. Это может быть не буквальная документация, а просто контекст того, как он появился: проектный документ с чёткой мотивацией, почему эта функция существует, и стратегией того, как она будет реализована.
- Отсутствие эксперта. Когда команда вносит изменения в код, есть ли человек, который сможет его проверить? Это часто можно заметить по обзорам кода, которые выглядят как быстрое «вроде правильно», потому что рецензенту не хватает контекста и знаний для проведения тщательного анализа. Наиболее вероятный сценарий: рассматриваемый код был написан кем-то, кто покинул команду, и никто больше не работал над этой частью кодовой базы.

Важно чётко понимать, почему с кодом сложно работать и что с этим можно сделать. Просто старый код, но с документацией и тестами, не является устаревшим кодом. Даже код, не имеющий тестов, но с хорошей документацией и известный команде, не обязательно легаси. Ситуацию можно улучшить, просто потратив время на добавление тестов. Тогда у нас будет просто старый, а не легаси-код.

3. Приоритет обновления легаси-кода
Как только код будет обоснованно признан «устаревшим», важно подумать о ценности, которую команда может получить, переписав или обновив код. Может возникнуть соблазн думать об обновлении всего легаси-кода, но это ошибочно. Допустим, есть два блока легаси-кода. Каким заняться в первую очередь?
Определите как часто блок кода должен меняться. Если один блок связан с критически важной функцией, то устаревший статус кода будет иметь огромное влияние, замедляя работу инженеров, снижая удовлетворённость и задерживая релизы.
С другой стороны, если устаревший код находится в блоке, к которому редко прикасаются, не имеет запланированных функций, которые вынудили бы его менять, и всё работает, не создавая проблем для пользователей, какой смысл в переписывании кода?

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

Окончание следует…

Источник:
https://leaddev.com/legacy-technical-debt-migrations/five-steps-managing-legacy-code
👍13
День 1836. #ЗаметкиНаПолях
Пять Шагов по Управлению Легаси-Кодом. Окончание

Начало

4. Постепенные улучшения
Как подойти к изменению кода? Здесь обычно используются два подхода: переписывание за раз или поэтапно. Как всегда в разработке ПО, серебряной пули не существует. Переписывание за раз рискованно и ставит ряд сложных вопросов:
- Что делать, если обнаружена ошибка? Исправить в старом коде, в новом или и там, и там?
- Что, если переписывание займёт больше времени, чем ожидалось? Придётся ли поддерживать две кодовые базы в течение значительного времени? Приведёт ли это к дублированию работы?
- Что, если нужно выпустить новую функцию по ходу переписывания? Можем ли мы изменять старый код?
- Как выкладывать новую версию? Один большой релиз в конце? Что, если что-то пойдёт не так? Т.е. мы не получим никаких отзывов или ощущения прогресса, пока не выпустим финальную версию?

Поэтапный подход предполагает, что мы делаем ряд мелких шагов к цели. У этого подхода есть свои недостатки (обычно он требует тщательного планирования этапов работы), но он позволяет снизить некоторые из упомянутых ранее рисков:
- Поэтапные релизы проходят легче, чем один большой в конце процесса.
- Мы избегаем создания отдельной базы кода, поэтому не рискуем поддерживать или дублировать работу в двух местах.
- Можно приостановить работу для выпуска новых функций, если необходимо (иногда это приходится делать).

5. Чёткое определение масштаба переписывания
Иногда проект может выйти за рамки поэтапного переписывания и потребовать более агрессивного подхода. При этом важно работать над снижением риска, т.е. жёстко контролировать объём переписывания. Иногда можно переписать всю кодовую базу частями, например, переписать уровень данных, а затем переписывать интерфейс, вместо того чтобы заниматься обеими задачами одновременно. Учитывая, что переписывание обычно требует приостановки каких-либо работ или изменений в оригинале, лучше сводить количество переписываний и их объём к минимуму.

Кроме того, большое переписывание, занимающее недели или месяцы, — это рискованный релиз: в рабочую среду одновременно выбрасывается множество изменений. Вместо этого лучше вносить изменения постепенно, например, скрыв изменения «флагом функции». Так код поставляется, но не выполняется приложением, пока не будет установлен флаг. Затем вы можете включить этот флаг для определённой группы пользователей — например, для внутреннего персонала — и убедиться, что всё работает. Если есть какие-либо проблемы, можно быстро отключить новый код, выключив флаг. Это позволяет оперативно реагировать на неожиданные проблемы (проблемы всегда будут, независимо от того, насколько вы осторожны и старательны). Как только перезапись будет завершена, и вы уверены, что она прошла успешно, можете удалить флаг функции и весь старый код.

Итого
Легаси-код явно никуда не денется. Продукты меняются, команды развиваются, а технологии совершенствуются. Часть кода, который вы пишете сегодня, в ближайшие годы станет устаревшим — и не по вашей вине! Ключевым моментом является умение использовать устаревший код и рассматривать его как интересную техническую задачу. Со временем, работая над этими проблемами, вы накопите массу опыта и инструментов для работы с устаревшим кодом. Вы сможете постепенно модернизировать его с минимальными неудобствами для своих пользователей и коллег, увеличивая охват тестирования, удовлетворённость разработчиков и качество кода. Нет ничего более приятного, чем пул-реквест, который удаляет остатки кода, над переписыванием которого вы работали несколько месяцев.

Источник: https://leaddev.com/legacy-technical-debt-migrations/five-steps-managing-legacy-code
👍14
День 1837. #Шпаргалка
Примеры Кода для Повседневных Задач
В этой серии представлю вам коллекцию фрагментов кода C#, охватывающих широкий спектр сценариев, с которыми вы можете столкнуться при разработке ПО.

I. Словари
Словари - гибкая структура данных для соединения пар элементов.

1. Объединение двух словарей
Обычная операция при работе со структурами данных. Объединение словарей может оказаться непростой задачей, особенно при наличии повторяющихся ключей. Что делать при этом, будет зависеть от ваших потребностей. Вот несколько примеров:
var dict1 = new Dictionary<string, string> { 
{ "Superman", "Flight" }
};
var dict2 = new Dictionary<string, string> {
{ "Batman", "Gadgets" }
};

// LINQ
var merged = dict1
.Concat(dict2)
.ToDictionary(x => x.Key, x => x.Value);

// Цикл foreach
foreach (var item in dict2)
dict1[item.Key] = item.Value;

// Метод расширения Union
var merged2 = dict1
.Union(dict2)
.ToDictionary(x => x.Key, x => x.Value);


2. Инвертирование
Что, если вам нужно поменять местами ключи и значения словаря? Операция может осложниться, если у вас неуникальные или нехешируемые значения:
var heroes = new Dictionary<string, string>
{
{ "Flash", "Super Speed" },
{ "Green Lantern", "Power Ring" },
{ "Aquaman", "Atlantean Strength" }
};

// LINQ
var inverted = heroes
.ToDictionary(x => x.Value, x => x.Key);

// Цикл foreach
var inverted2 = new Dictionary<string, string>();
foreach (var item in heroes)
inverted2[item.Value] = item.Key;


3. Обратный поиск
Обратный поиск (найти ключ для данного значения) может быть полезен, когда словарь слишком велик для инвертирования:
var dimensions = new Dictionary<string, int>
{
{ "length", 10 },
{ "width", 20 },
{ "height", 30 }
};

int val = 20;

// "В лоб" – первый ключ
foreach (var d in dimensions)
{
if (d.Value == val)
{
Console.WriteLine($"{d.Key}: {d.Value}");
break;
}
}

// "В лоб" – все ключи
foreach (var d in dimensions)
{
if (d.Value == val)
Console.WriteLine($"{d.Key}: {d.Value}");
}

// LINQ – первый ключ
var key = dimensions
.FirstOrDefault(x => x.Value == val)
.Key;

// LINQ – все ключи
var keys = dimensions
.Where(x => x.Value == val)
.Select(x => x.Key);

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

Источник: https://medium.com/bytehide/100-csharp-code-snippets-for-everyday-problems-e913c786dec9
👍17👎3
День 1838. #ProjectManagement
Чтобы Избавиться Технического Долга, Оцените Его. Начало
Когда Уорд Каннингем придумал метафору технического долга, ему нужен был способ обсудить решения, принятые на ранних этапах проекта, которые мешали инженерам в дальнейшей работе над проектом. Он занимался финансовым ПО - отсюда финансовая метафора. Технические решения, которые команда приняла на раннем этапе ради вывода продукта на рынок, возможно, вредят впоследствии, и, если их не исправить, производительность команды пострадает, а новые функции будут выпускаться медленнее.

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

На самом деле, проблема обновления устаревшего фреймворка или библиотеки не является технической. Как и в метафоре, она финансовая. Множество обновлений откладываются на долгие годы из-за необходимости установки нового ПО, переписывания кода и проверки последствий обновления. При этом неисправленные дыры в безопасности могут сделать проект уязвимым, а сложность выпуска новых функций может поставить приложение в невыгодное положение на рынке. Когда-нибудь этот счёт придётся оплатить.

Технический долг – это не только обновления языка и инструментов. Это могут быть добросовестные решения при написании кода, принятые ради немедленной выгоды. Чем раньше вы сможете вернуть долги, тем лучше. Но возврат долгов требует точного определения размера долга, который несёт команда.

Стоимость времени обслуживания
Разработчики любят решать проблемы, но эта любовь не всегда распространяется на поиск ошибок и замену устаревших технологий. Однако, какие тикеты попадут в следующий спринт, определяет менеджмент. Разработчики могут стремиться писать наиболее элегантный и чистый код, но менеджер служит бизнесу, а бизнес часто фокусируется на прибылях и убытках. Чтобы погасить технологический долг, сначала необходимо оценить его с точки зрения затрат и выгод.

Экономические последствия технического долга вполне реальны. В 2018 году Stripe провела исследование влияния техдолга и других эффектов «плохого кода». Они обнаружили, что средний разработчик в неделю тратил 13,5 часов на техдолг и ещё почти 4 часа на «плохой код». Т.е. почти половину рабочего времени! Если вы умножите это на зарплату разработчика, то получите серьёзные затраты на техдолг.

Поддержка некачественного кода часто занимает значительно больше времени из-за сложности, а также обычно влечёт больше ошибок. Таким образом, низкое качество в итоге серьёзно влияет на то, что ценят менеджеры. Большинство компаний уже используют какую-либо систему отслеживания проблем, поэтому разработчики, которые хотят обосновать стремление избавиться от техдолга, могут использовать её. Это просто требует дисциплины в отслеживании тикетов, оценке стори-пойнтов и подтверждении времени, потраченного на обслуживание техдолга.

Также можно просто спросить команду. Если команда признаёт что-то важным, они, вероятно, либо потратили некоторое время на это недавно (т.е. это свежо у них в голове), либо код настолько плох, что работа над ним надолго запомнилась.

Описанное выше - это всего лишь затраты на написание кода для избавления от техдолга. Ещё одна важная метрика — это код, который вы НЕ написали.

Окончание следует…

Источник:
https://stackoverflow.blog/2023/08/24/if-you-want-to-address-tech-debt-quantify-it-first/
👍11
День 1839. #ProjectManagement
Чтобы Избавиться Технического Долга, Оцените Его. Окончание

Начало

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

Техдолг влияет на то, сколько времени потребуется на написание нового кода, особенно если, избегая избавления от техдолга, вы добавляете костыли, которые увеличивают количество путей прохождения кода (цикломатическую сложность). Эта сложность сама по себе становится частью долга, который придётся в какой-то момент оплатить.

Существует связь между этой сложностью и продуктивностью разработчиков. Т.к. код становится сложнее поддерживать, новые функции занимают больше времени. Чем больше мест в коде необходимо затронуть, чтобы изменение заработало, тем больше времени это занимает.

Иногда техдолг возникает из-за добросовестных решений, которые устарели или основаны на старых версиях ПО. Их обновление может потребовать серьёзного переписывания, а не просто рефакторинга. Вот несколько признаков того, что код требуется переписать:
- ПО устарело или скоро потеряет поддержку, или доступна версия лучше.
- Вы не можете автоматизировать развёртывание.
- Тестирование занимает слишком много времени, не может быть автоматизировано или не может охватить важные функции.

Если у вас есть такая статистика, вы можете сравнить вашу текущую скорость выпуска новых функций с лучшим спринтом, который часто приходится на начало жизненного цикла ПО. Разницу можно считать процентами по техническому долгу. По мере роста долга растут и время, и усилия, затрачиваемые на погашение этих процентов. Чем медленнее общая скорость разработки, тем меньше новых функций будет поставлено клиентам.

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

Адаптация — первая и самая важная часть опыта сотрудника в компании. Чтобы освоиться новому сотруднику может потребоваться до двух месяцев. Неудачный опыт адаптации может отпугнуть разработчика. 20% уходят в течение первых 45 дней. Т.е. плавный процесс адаптации может означать разницу между получением хорошего специалиста и новым поиском.

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

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

Очевидно, техдолг — не просто код, который требует рефакторинга для соответствия лучшим практикам: устаревшие или неэффективные инструменты и зависимости тоже считаются. В опросе StackOverflow о том, почему разработчики решают остаться на работе или уйти 35-40% сказали, что ищут новую работу, чтобы использовать новые технологии.

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

Источник: https://stackoverflow.blog/2023/08/24/if-you-want-to-address-tech-debt-quantify-it-first/
👍14
День 1840. #ЧтоНовенького #CSharp13
Улучшения SearchValues в .NET 9
Продолжаем заглядывать в будущее .NET.

Класс System.Buffers.SearchValues<T>, представленный в .NET 8, предназначен для эффективного поиска набора байтов или символов в другом наборе, например, в реализации String.IndexOfAny(char[]). При создании экземпляра SearchValues<T> все данные, необходимые для оптимизации будущего поиска, вычисляются заранее и выбирается наиболее эффективный алгоритм поиска.

Вот простой пример:
var searchValues = SearchValues.Create(
new[] { 'a', 'e', 'i', 'o', 'u' });

Console.WriteLine(
ContainsVowel("Hello, World!")); // True

bool ContainsVowel(ReadOnlySpan<char> text)
=> text.ContainsAny(searchValues);


Пока мы ограничены поиском только символов. Но гораздо чаще мы хотим искать строковые значения, то есть текст, внутри другого текста. В .NET 9 обещают это ввести! Появились новые перегрузки, и SearchValues можно будет применять в поиске текста:
var names = SearchValues.Create(
["Steven", "Sherlock", "Holmes", "Michael", "Scott"],
StringComparison.OrdinalIgnoreCase);

var text = "This is Steven and Michael. You know Michael Scott from the office.";

Console.WriteLine(
MemoryExtensions.ContainsAny(text, names)); // True


Кроме того, есть предложение добавить SearchValues в регулярные выражения.

Источник: https://steven-giesel.com/blogPost/080c8f82-f376-489f-a304-72d419978294/searchvalues-object-become-better-with-net-9
👍22
День 1841. #ВопросыНаСобеседовании #ASPNET
Самые часто задаваемые вопросы на собеседовании по C#

28. Как сервер Kestrel работает в среде .NET Core и чем он отличается от других веб-серверов?

Kestrel — кроссплатформенный веб-сервер, созданный для приложений на базе .NET Core. Его также можно использовать в сочетании с обратным прокси-сервером, таким как Apache, Nginx или IIS, который обеспечивает дополнительный уровень конфигурации, безопасности и балансировки нагрузки.

Ключевые особенности:
- Кроссплатформенность.
- Высокая производительность: оптимизирован для эффективной обработки большого количества одновременных подключений.
- Легковесность: оптимизирован для работы в средах с ограниченными ресурсами, таких как контейнеры.
- Повышенная безопасность: поддерживает HTTPS и защищён от уязвимостей веб-сервера.
- Широкая поддержка протоколов: HTTP/1.1, HTTP/2 и HTTP/3, WebSocket.
- Бесшовная интеграция с компонентами ASP.NET Core, такими как конвейер промежуточного ПО, внедрение зависимостей и система конфигурации.
- Множество рабочих нагрузок: ASP.NET (минимальные API, MVC, страницы Razor, SignalR, Blazor и gRPC), а также обратные прокси с помощью YARP.
- Расширяемость: возможность настройки с помощью конфигурации, промежуточного ПО и т.п.
- Встроенные функции диагностики производительности, такие как ведение журнала и метрики.

Место, которое Kestrel занимает в процессе обработки запроса показано на рисунке ниже. Обратный прокси (Apache, Nginx или IIS) пересылает запрос в веб-сервер ASP.NET Core (по умолчанию Kestrel). Kestrel принимает низкоуровневый сетевой запрос и использует его для создания объекта HttpContext, который может использовать остальная часть приложения. Веб-сервер заполняет HttpContext подробностями исходного HTTP-запроса и другими деталями конфигурации и передаёт их остальной части приложения.

Kestrel отвечает за получение данных запроса и создание представления запроса на C#, но не пытается обрабатывать запрос напрямую. Для этого он передаёт HttpContext в конвейер промежуточного ПО, где выполняются стандартные для всех запросов операции вроде журналирования, обработки исключений или обслуживания статических файлов.

После конвейера промежуточного ПО запрос попадает в конвейер MVC. Он отвечает за создание HTML-кода страницы ответа. Не каждому приложению нужен конвейер MVC, но обычно его используют большинство приложений, отображающих HTML-ответ пользователю. Далее HTML-ответ возвращается по цепочке обратно и отправляется клиенту.

Источники:
-
https://dev.to/bytehide/net-core-interview-question-answers-4bc1
- Эндрю Лок “
ASP.NET Core в действии”. 2-е изд. – М.: ДМК Пресс, 2021. Глава 2.
👍11👎1
День 1842. #Карьера
Сеньор, Эксперт или Кто? Начало
Кто такой сеньор? Как им стать? Имеет ли это вообще значение? Давайте рассмотрим некоторые аспекты при «оценке» чьих-либо навыков.

Зрелость
Что значит быть зрелым? Многие считают, что важно указывать на плохие стороны решений. Неважно, говорим ли мы о разработке ПО, дорогах, налогах или о чём-то ещё, что люди любят обсуждать. Хотя может показаться, что хорошие инженеры (в целом профессионалы) могут найти недостатки решений и определить, где они не работают, это не то, что нам нужно. Рассмотрим некоторые уровни профессионализма людей и их особенности.

1. Просто жаловаться
Это легко. «Налоги надо снизить». «Этот код не работает, надо исправить». Оба эти утверждения могут быть на 100% верными, но при этом совершенно бесполезными. Легко «просто жаловаться», сложно объяснить, почему что-то не так, и как это исправить. В разработке мы можем делать такие утверждения буквально обо всем: о языке программирования, технологии, библиотеке, фреймворке, конкретном решении или чём-то ещё. Это ничего не приносит.

2. Уметь жаловаться
Это сложнее. На этом уровне человек может легко указать на недостатки конкретного решения и объяснить, что они означают. Более того, человек часто оказывается прав. Например, может объяснить, почему эта библиотека недостаточно хороша, почему код нечитабелен, почему это решение работает медленно или может найти крайние случаи, когда решение потерпит неудачу. Но это всё равно не то, что нужно. Реальность никогда не бывает идеальной. Мы не можем сделать код (налоги, дороги и т.д.) идеальным и избежать всех проблем. Недостаточно просто показать, где что-то не работает и что есть недостатки, потому что недостатки есть у всего. Интересно, что многие архитекторы ПО находятся на этом уровне, потому что всегда могут сказать, «чего не делать», но никогда не смогут предложить лучшее решение.
Другой пример: программист может предложить множество вариантов, но не может решить, какой выбрать, потому что у всех есть какие-то проблемы. Позже они обычно навязывают решение клиенту, владельцу продукта или архитектору ПО, а затем могут жаловаться, что было принято неправильное решение.

3. Предоставлять решения
Эти люди могут высказывать идеи (и даже критиковать их) и принимать решения. Даже если они понимают, что всё не будет идеально, они могут пойти на риск или сознательно выбрать что-то, что не будет работать идеально.
Важно понимать, что, если человек сделает выбор, его всегда будут критиковать. Потому что невозможно выбрать идеальное решение. Поэтому, если вы хотите стать достаточно зрелыми и достичь этого уровня, вам нужно смириться с тем, что вас всегда будут критиковать. Неважно программист вы, архитектор ПО или политик.

Сеньорность
Что значит быть сеньором? Дело не только в навыках, а в правильном отношении, навыках и опыте.

1. Джун
Не может работать самостоятельно из-за недостатка опыта и навыков и нуждается в помощи и надзоре, чтобы добиться прогресса. Некоторые утверждают, что «X — не джунская позиция», где X может быть кем угодно (scrum-мастер, владелец продукта, менеджер проекта). Но, по сути, независимо от роли, на начальном этапе любому понадобится некоторая помощь и надзор.

2. Мидл
Может работать самостоятельно, но ничем не отличается от других. Он «просто делает свою работу». На него можно положиться, не нужно его контролировать, и можно ожидать, что у него достаточно навыков для выполнения работы.

3. Сеньор
Сеньоры понимают, в чём заключается их роль и как она взаимодействует с другими ролями вокруг. Они могут совершенствоваться в роли и не только в своей. Могут растить других, делиться знаниями, обучать и адаптироваться к меняющимся условиям.
Это не означает, что сеньоры обладают отличными навыками. Зачастую это не так. Но они могут эффективно использовать свои навыки и понимают, как повысить уровень себя и окружающих. Они используют весь свой потенциал и раскрывают весь потенциал окружающих.

Окончание следует…

Источник:
https://blog.adamfurmanek.pl/2023/02/24/types-and-programming-languages-part-19/index.html
👍12
День 1843. #Карьера
Сеньор, Эксперт или Кто? Окончание

Начало

Старший инженер, архитектор и другие
Означает ли изложенное вчера, что сеньорам не обязательно хорошо разбираться в программировании? Или что, чтобы стать архитектором, нужно учить других? Есть две основные вещи, которые мы можем выделить в разработке ПО: роли и навыки.

Роль
Инженер-программист — это роль. То же самое и с архитектором. Каждая роль требует определённого набора навыков, а разные роли могут требовать схожих навыков.
При этом «архитектор» — не «следующий уровень после сеньора», а отдельная роль. Она требует других навыков и даёт другие результаты. Поэтому не обязательно становиться сеньором, прежде чем стать архитектором. То же касается владельцев продуктов, менеджеров проектов и т.п.
Также архитекторам не обязательно быть «экспертами» в программировании. Как может быть младший программист, может быть и младший архитектор. Это просто другая роль.

Навыки
Каждая роль требует навыков. Некоторые навыки могут потребоваться для многих должностей, например, работа с числами необходима и бухгалтерам, и продавцам. Можно измерить ваши навыки, и обычно можно сказать, что вы новичок, профессионал или эксперт. В разработке ПО мы можем распознать множество аспектов навыков:
1. Технология
Язык программирования, база данных, фреймворк, библиотека, парадигма, приложение или что-то ещё. Например, эксперт по C# сможет объяснить, как работает GC, как реализуются блокировки или почему мы не можем наследовать от структур.

2. Область
Определённая часть приложения: бэкенд, фронтенд, инфраструктура, база данных и т.п. Например, эксперт по веб-бэкенду сможет объяснить SNI, CORS, SOP, сертификаты, масштабирование, кэширование и другие вещи, обычно используемые в веб-серверах.

3. Домен
Определённая часть реальности, которую мы моделируем в ПО: платежи, медицина, торговля или логистика. Например, эксперт в банковском деле объяснит, что такое кредитный рейтинг, как его рассчитать, что такое PCI, как работать с международными транзакциями, что такое ELIXIR, SEPA или SORBNET.

Кто я?
Исходя из вышесказанного, возможно, вы старший инженер-программист + эксперт по бэкэнду + младший специалист в C# + профессионал в банковском деле. Именно поэтому и могут существовать архитекторы ПО, которые не умеют программировать.

Программист или разработчик ПО?
Программирование и разработка ПО - это лишь вопрос названия. Важно понимать, что «программирование» – не единственное, что есть в «разработке ПО». Легко написать код. Трудно поддерживать код на протяжении многих лет, когда технологии меняются, операционные системы устаревают, а фреймворки исчезают. Не имеет значения, называем ли мы себя программистами или разработчиками ПО. Важно то, сможем ли мы написать код или разрабатывать одну и ту же кодовую базу на протяжении десятилетий.

А теперь самое сложное. Когда кто-то ищет «сеньоров», можем ли мы сказать, кого они имеют в виду?
Короткий ответ: нет. Вы не узнаете, пока не спросите их, что они под этим подразумевают. И именно так следует искать работу: просто сопоставьте, каковы их ожидания, что вы умеете делать, насколько вы в этом хороши и что вы получаете взамен. Неважно, назовут ли вас джуном, сеньором, архитектором, директором, помощником или экспертом. Это вообще не имеет значения (если отбросить психологические аспекты). Важно то, какова ваша роль и чего от вас ожидают.

Источник: https://blog.adamfurmanek.pl/2023/02/24/types-and-programming-languages-part-19/index.html
👍8
Класс UserSignup имеет свойства Email и EmailConfirmation. Какой атрибут аннотаций данных использовать для свойства EmailConfirmation, чтобы проверить его равенство свойству Email?
#Quiz #ASPNET
Anonymous Quiz
28%
[Validate(x => x == this.Email)]
27%
[Equals("Email")]
18%
[Compare("Email")]
26%
[Match("Email")]
👍11
День 1844. #Шпаргалка
Примеры Кода для Повседневных Задач

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

II. Списки. Начало
Среди различных структур данных списки выделяются как наиболее распространённые. В C# список представляет собой «динамический массив». Мы можем добавлять и удалять элементы, не беспокоясь о лежащей в основе реализации, что делает списки интуитивно понятными в обращении.

1. Добавление элемента
C# предлагает множество способов добавления элементов в список:
// Статическая инициализация
var list = new List<int> {1, 2};
// Начиная с C# 12
List<int> list2 = [2, 3];

// Добавление - Add
list.Add(3); // [1, 2, 3]
// Добавление списка - AddRange
list.AddRange(new List<int> {4, 5});
// [1, 2, 3, 4, 5]

// Начиная с C# 12 – оператор расширения
List<int> list3 = [..list2, 4];
// [2, 3, 4]

// Вставка - Insert
list2.Insert(0, 1);
// [1, 2, 3]

// Вставка списка - InsertRange
list2.InsertRange(list2.Count, new List<int> {4, 5});
// [1, 2, 3, 4, 5]

См. подробнее про оператор расширения.

2. Получение последнего элемента
C# предлагает несколько интересных альтернатив:
List<string> list = ["red", "blue", "green"];

// Стандартно через Count
var last = list[list.Count - 1];
// LINQ
last = list.Last();
// индексатор
last = list[^1];


3. Проверка пуст ли список
И снова, есть несколько вариантов (на всякий случай, добавим проверку на null):
// Метод Count
if ((list?.Count ?? 0) == 0)
{
// список пуст
}
// LINQ
if (list?.Any() != true)
{
// список пуст
}


4. Клонирование списка
При работе со ссылочными типами всегда следует помнить, что простое присваивание их другой переменной копирует только ссылку:
List<int> list = [1, 2, 3];
// LINQ
var duplicate = list.ToList();
// Конструктор
duplicate = new List<int>(list);
// Начиная с C# 12 – оператор расширения
duplicate = [..list];


Окончание следует…

Источник:
https://medium.com/bytehide/100-csharp-code-snippets-for-everyday-problems-e913c786dec9
👍21
День 1845. #Шпаргалка
Примеры Кода для Повседневных Задач

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

II. Списки. Окончание
Начало

5. Генераторы списков
List comprehension — мощная функция Python, название которой сложно перевести на русский. Назовём это просто генерацией списков. В C# нет прямого эквивалента, но можно добиться аналогичной функциональности, используя LINQ:
List<int> list = [1, -2, 3];

// Преобразование
var squares = list
.Select(i => i*i).ToList();

// Фильтрация
var positive = list
.Where(i => i > 0).ToList();

// Все возможные пары
var list2 = new List<int> { 4, 5, 6 };
var pairs = list
.SelectMany(a => list2, (a, b) => (a, b))
.ToList();

И т.п.

6. Попарная обработка элементов двух списков
Представьте, что у вас есть два списка, и ваша цель — объединить их в один путём, например, попарного суммирования элементов:
List<int> list = [1, 2, 3, 4, 5, 6];
List<int> list2 = [4, 8, 15, 16, 23, 42];

// «В лоб» в цикле
var sum = new List<int>();
for (int i = 0; i < list.Count; i++)
sum.Add(list[i] + list2[i]);

// LINQ метод Zip
sum = list
.Zip(list2, (x, y) => x + y).ToList();

Замечание: в отличие от примера «в лоб», метод Zip корректно обрабатывает ситуации, когда списки разной длины. Длина результирующего списка будет равна длине меньшего из списков.

7. Сортировка
Сортировка строк (или сложных объектов) имеет свои особенности, в которые мы не будем здесь углубляться. Отметим, что у нас есть несколько вариантов:
List<string> list = ["leaf", "cherry", "Fish"];

// «На месте»
list.Sort();
// Без учёта регистра
list.Sort(StringComparer.OrdinalIgnoreCase);

// в новый список
var sorted = list
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
.ToList();

Если требуется сортировка объектов по какому-либо свойству, метод Sort также может принимать компаратор или лямбда-выражение для сравнения объектов между собой. См. подробнее в конце этого поста.

Источник: https://medium.com/bytehide/100-csharp-code-snippets-for-everyday-problems-e913c786dec9
👍12