.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
День пятьсот сорок третий. #DotNetAZ
Dotnet A-Z. 4
В этой серии постов рассмотрим наиболее распространённые понятия в .NET в алфавитном порядке.

implementation of .NET (реализация .NET)
Реализация .NET включает в себя:
- Одну или несколько сред исполнения: CLR, CoreCLR, CoreRT.
- Библиотеку классов, которая реализует версию .NET Standard и может включать дополнительные API: .NET Framework Base Class Library, .NET Core Base Class Library.
- Необязательно: один или несколько фреймворков приложений: ASP.NET, Windows Forms и WPF включены в .NET Framework.
- Необязательно: инструменты разработки. Некоторые инструменты разработки используются несколькими реализациями.
Примеры реализаций .NET:
- .NET Framework – Реализация .NET, которая работает только в Windows.
- .NET Core – Кроссплатформенная, высокопроизводительная реализация .NET с открытым исходным кодом.
- Universal Windows Platform (UWP) – Реализация .NET, которая используется для создания современных приложений с сенсорным управлением и для ПО Интернета вещей (IoT).

Library (библиотека)
Коллекция API, которая может быть вызвана из приложений или других библиотек. Библиотека .NET состоит из одной или нескольких сборок.
Термины библиотека и фреймворк часто используются взаимозаменяемо.

Metapackage (метапакет)
Пакет NuGet, это пакет, который не содержит сборок, но содержит список зависимостей. Используется для лёгкого добавления заданного набора библиотек в проект, т.к. достаточно установить только метапакет и все его зависимости будут автоматически загружены и подключены.
Например, метапакет Microsoft.AspNetCore.App предоставляет набор API по умолчанию для создания приложения ASP.NET Core.

Источник: https://docs.microsoft.com/en-us/dotnet/standard/glossary
День пятьсот сорок четвёртый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
52. Дайте Проекту Голос
Ваш проект скорее всего использует систему контроля версий. Возможно, он подключен к серверу непрерывной интеграции, который проверяет правильность кода с помощью автоматических тестов. Это замечательно.

Вы можете добавить инструменты статического анализа кода на сервере непрерывной интеграции для сбора метрик кода. Эти метрики предоставляют обратную связь о конкретных аспектах вашего кода, а также об их изменении с течением времени. Если вы устанавливаете метрики кода, всегда будет некоторая граница, которую вы не захотите пересекать. Предположим, вы начали с 20% покрытия тестами и никогда не хотите падать ниже 15%. Непрерывная интеграция помогает отслеживать все эти цифры, но вам всё равно придётся регулярно их проверять. Но представьте, что вы могли бы делегировать эту задачу самому проекту, позволив ему сообщать, когда метрики ухудшаются.

Вам нужно дать право голоса вашему проекту. Информирование разработчиков может быть сделано по электронной почте или с помощью мгновенных сообщений. Но ещё эффективнее будет использование в вашем офисе устройства экстремальной обратной связи (XFD).

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

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

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

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

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Daniel Lindner.
👍1
День пятьсот сорок пятый. #ЧтоНовенького #CSharp9
C#9: Незначительные Улучшения в Лямбдах
В C#9 лямбда-функции получат два обновления. Ни одно из них не изменит способ написания кода, но они помогут разработчику прояснить свои намерения.

Дискард-Параметры Лямбда Функций
Позволят разработчикам явно указать, что некоторые параметры не нужны, что предотвратит ошибочные предупреждения компилятора о неиспользуемых параметрах. Это может быть полезно, например, в обработчиках событий, когда не нужны параметры sender и eventArgs:
button1.Click += (s, e) => ShowDialog();
Замена параметров, как показано ниже, позволит явно указать, что они не используются:
button1.Click += (_, _) => ShowDialog();
При необходимости могут быть использованы типы:
var handler = (object _, EventArgs _) => ShowDialog();

Статические Анонимные Функции
Будут использоваться, чтобы обозначить, что лямбда или анонимная функция не может захватывать локальные переменные (включая параметры). Вот пример из оригинального предложения функционала:
int y = 10;
someMethod(x => x + y);
//захватывает 'y', приводя к неявному выделению памяти

Проблема в том, что это неявно приводит к увеличению времени жизни локальной переменной, т.к. анонимная функция может существовать дольше, чем окружающий её метод.
Чтобы избежать случайного захвата любого локального состояния при предоставлении лямбда-функций в качестве аргумента метода, предлагается добавить к лямбда-объявлению ключевое слово static. Это сделает лямбда-функцию похожей на статический метод, который не может захватывать локальные объекты и не имеет доступа к this или base:
int y = 10;
someMethod(static x => x + y); //ошибка!

Чтобы исправить эту ошибку, переменная y должна быть изменена на константу или статическое поле:
const int y = 10;
someMethod(static x => x + y);

Вот основные правила для статических анонимных функций:
- может ссылаться на статические члены из окружающего кода;
- может ссылаться на определения констант из окружающего кода;
- не может захватывать состояние из окружающего кода, т.е. локальные объекты, параметры и this из окружающего кода недоступны;
- не может ссылаться на экземплярные члены окружающего её класса;
- nameof() внутри статической анонимной функции может ссылаться на локальные объекты, параметры, this или base из окружающего кода.

Источник: https://www.infoq.com/news/2020/07/CSharp-Lambdas/
День пятьсот сорок шестой.
7 Опасных Ошибок, Которые Легко Совершить в C#/.NET. Начало 1-2
В каждом языке есть ловушки, в которые легко попасть и ошибочные представления об ожидаемом поведении языка. Вот некоторые из них.

1. Непонимание Отложенного Исполнения
Опытные разработчики хорошо осведомлены об этой функции .NET, но она может испортить жизнь тем, кто о ней не знает. Если коротко, методы/операторы, возвращающие IEnumerable<T> через yield, выполняются не на строке вызова метода/оператора, а когда к результирующей коллекции обращаются каким-либо образом. То же относится к большинству методов LINQ.

Рассмотрим следующее выдуманное модульное тестирование:
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void Ensure_Null_Exception_Is_Thrown() {
var result = RepeatString5Times(null);
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void Ensure_Invalid_Operation_Exception_Is_Thrown() {
var result = RepeatString5Times("test");
var firstItem = result.First();
}

private IEnumerable<string> RepeatString5Times(string toRepeat) {
if (toRepeat == null)
throw new ArgumentNullException(nameof(toRepeat));
for (int i = 0; i < 5; i++) {
if (i == 3)
throw new InvalidOperationException("3 ужасное число");
yield return $"{toRepeat} - {i}";
}
}

Оба теста не пройдут. Первый, потому что к result ни разу не обращаются и тело метода не вызывается. Второй, т.к. механизм отложенного выполнения выйдет из метода, когда это необходимо (т.е. после выдачи первого элемента), поэтому i == 3 никогда не выполнится.

2. Предположение о Порядке Элементов в Словаре
Элементы в List<T> сохраняются в том же порядке, в котором вы их добавляете. Но иногда нужно иметь объект, связанный с элементом списка, и очевидным ответом является использование Dictionary<TKey, TValue>, который позволяет указать связанное значение для ключа. Вы можете выполнить итерацию по словарю, используя foreach, и большую часть времени он будет вести себя так, как ожидалось: вы будете получать доступ к элементам в порядке их добавления. Однако порядок элементов словаря не определён, т.е. это счастливое совпадение, и на это поведение не стоит полагаться. Это объясняется в документации Microsoft, но кто ж её читает))) Следующий код:
var dict = new Dictionary<string, object>();        
dict.Add("first", new object());
dict.Add("second", new object());
dict.Remove("first");
dict.Add("third", new object());
foreach (var entry in dict)
Console.WriteLine(entry.Key);

Выведет:
third
second

Продолжение следует…

Источник:
https://chrisstclair.co.uk/7-dangerous-mistakes-in-c-net-that-are-easy-to-make/
День пятьсот сорок седьмой.
7 Опасных Ошибок, Которые Легко Совершить в C#/.NET. Продолжение 3-4
В каждом языке есть ловушки, в которые легко попасть и ошибочные представления об ожидаемом поведении языка. Вот некоторые из них.
Начало 1-2.

3. Игнорирование Безопасности Потоков
Многопоточность великолепна. При правильной реализации может произойти значительное улучшение производительности вашего приложения. Однако вы должны быть осторожны с объектами, которые вы изменяете, потому что могут возникать, на первый взгляд, случайные ошибки.

Многие классы библиотеки .NET не являются потокобезопасными, т.е. Microsoft не даёт никаких гарантий правильной работы класса при использовании параллельно из нескольких потоков. Это не было бы большой проблемой, если бы можно было сразу отлавливать возникающие проблемы, но природа многопоточности предполагает, что проблемы изменчивы и возникают непредсказуемо: скорее всего, каждое выполнение кода будет приводить к иному результату.

В качестве примера возьмем этот блок кода, который использует простой, но не потокобезопасный List<T>:
var items = new List<int>();
var tasks = new List<Task>();
for (int i = 0; i < 5; i++) {
tasks.Add(Task.Run(() => {
for (int k = 0; k < 10000; k++)
items.Add(i);
}));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine(items.Count);

Мы добавляем числа от 0 до 4 в список по 10000 раз каждое, т.е. мы должны получить список в 50000 элементов, верно? Ну, есть небольшой шанс, что так и получится, но ниже мои результаты 5 выполнений:
28191
23536
44346
40007
40476
Попробуйте сами

Так получается, потому что метод Add не является атомарным, т.е. поток может «прервать» исполнение метода. То есть размер массива может измениться, в то время как другой поток находится в процессе добавления элемента, либо два потока могут добавлять элементы с одним индексом. Иногда могут возникать исключения IndexOutOfRange или ArgumentException, вероятно, потому что размер массива изменился во время добавления к нему элемента. Что делать? Мы могли бы использовать ключевое слово lock, чтобы гарантировать, что только один поток может добавлять элемент в список одновременно, но это может значительно повлиять на производительность. Microsoft любезно предоставляет несколько потрясающих коллекций, которые безопасны для потоков и оптимизированы для производительности.

4. Неправильное Округление
Теперь о чём-то более простом. .NET имеет прекрасный статический метод Round в классе Math, который принимает числовое значение и округляет до заданного десятичного знака. Работает обычно идеально, но что делать, когда вам нужно округлить 2.25 до десятых?
Math.Round(2.25, 1);
Вероятно, вы ожидаете, что это округлится до 2.3 – ведь нас так учили в школе. Однако, похоже, .NET использует «округление банкиров» и округляет приведенный пример до 2.2! Банкиры в таком случае округляют до ближайшей чётной цифры. К счастью, это можно легко переопределить в методе Math.Round:
Math.Round(2.25, 1, MidpointRounding.AwayFromZero);
По умолчанию используется MidpointRounding.ToEven.

Продолжение следует…

Источник:
https://chrisstclair.co.uk/7-dangerous-mistakes-in-c-net-that-are-easy-to-make/
День пятьсот сорок восьмой.
7 Опасных Ошибок, Которые Легко Совершить в C#/.NET. Продолжение 5-6
В каждом языке есть ловушки, в которые легко попасть и ошибочные представления об ожидаемом поведении языка. Вот некоторые из них.
Начало 1-2
Продолжение 3-4

5. Ужасный Класс "DBNull"
У некоторых это может вызвать неприятные воспоминания, т.к. ORM скрывает это зло от нас, но если вы используете чистый ADO.NET (SqlDataReader и т.п.), вы рано или поздно столкнётесь с DBNull.Value.

Я не уверен на 100%, почему в Microsoft решили представить NULL в виде специального типа DBNull со статическим полем Value. Возможно, причина в обратной совместимости. Так было в Visual Basic в эпоху до .NET. VB6 не имеет унифицированной объектной модели (когда всё наследуется от System.Object) или концепции «null». Существует Nothing, но это скорее default из C#, чем null. Таким образом, в VB6 и ADO, у вас есть значение DBNull для представления null из БД.

Разница может показаться незначительной, но значения DBNull и null имеют разную семантику. Например, в строках. В VB нулевая строка равна пустой строке. Нет никакого способа разделить эти две концепции как в VB6, так и VB7+ (VB.NET).

Единственное преимущество этого - вы не получите NullReferenceException при доступе к полю базы данных, равному NULL. Однако при этом вы не только должны поддерживать отдельный способ проверки значений на NULL (о чём можно легко забыть, и что может привести к серьезным ошибкам), но также вы теряете прекрасные возможности языка C#. Например, вместо:
reader.GetString(0) ?? "NULL";
придётся использовать:
reader.GetString(0) != DBNull.Value ? reader.GetString(0) : "NULL";
Ужас!

6. Злоупотребление ленивой загрузкой в LINQ
Ленивая загрузка - это отличная функция как LINQ to SQL, так и LINQ to Entities (Entity Framework), которая позволяет загружать связанные данные таблицы по требованию. Допустим, у нас есть таблицы Modules и Results с отношением «один ко многим» (модуль может иметь много результатов).

Когда нужно получить данные определённого модуля, но не нужны относящиеся к нему результаты, Entity Framework достаточно умён, чтобы запросить данные только для модуля, а для получения результатов выполнить отдельный запрос, только когда они потребуются. Таким образом, приведенный ниже код будет выполнять как минимум 2 запроса: один для получения модуля, а другой для получения результатов (для каждого модуля).
using (var db = new DBEntities()) {
var modules = db.Modules;
foreach (var module in modules) {
var moduleType = module.Results;
//Обработка модуля
}
}

Однако, если у нас много модулей, отдельный SQL запрос к результатам будет выполняться для каждого модуля. Очевидно, что это лишняя и ненужная нагрузка на сервер. Но в Entity Framework решить проблему очень легко, просто запросив включение результатов в исходный запрос:
var modules = db.Modules.Include(b => b.Results);
В этом случае выполнится всего один SQL запрос, который будет включать все модули и все результаты для каждого модуля, что Entity Framework потом корректно транслирует в объекты модели.

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

Источник:
https://chrisstclair.co.uk/7-dangerous-mistakes-in-c-net-that-are-easy-to-make/
День пятьсот сорок девятый.
Хороших выходных вам, дорогие подписчики. И вот вам видосик скрасить досуг первого дня авгрусти (запасайтесь двумя часами). На этот раз (большая редкость) видео на русском. Андрея Акиньшина в мире .NET лишний раз представлять не нужно. Его (по крайней мере, в русскоязычном сообществе) должны знать примерно как Рихтера или Скита. Впрочем, авторы видео его и не представляют, поэтому, если вы таки не знаете, кто это, сначала погуглите)))
В интервью каналу «Мы обречены» он рассказывает о своей книге «Pro .NET Benchmarking», про производительность и красоту кода, про хобби программистов и многое другое. В общем, лично мне очень понравилось.
День пятьсот пятидесятый.
7 Опасных Ошибок, Которые Легко Совершить в C#/.NET. Окончание 7
В каждом языке есть ловушки, в которые легко попасть и ошибочные представления об ожидаемом поведении языка. Вот некоторые из них.
Начало 1-2
Продолжение 3-4
Продолжение 5-6

7. Непонимание Того как LINQ to SQL/Entity Framework Генерирует Запросы
Продолжая тему из пункта 6, стоит упомянуть, насколько по-разному будет выполняться ваш код, если он находится внутри запроса LINQ. Если коротко, весь код внутри запроса LINQ транслируется в SQL. Это кажется очевидным, но очень легко забыть контекст, в котором вы находитесь и допустить ошибку. Ниже приведён список некоторых типичных проблем, с которыми вы можете столкнуться.

Большинство методов не будут работать
Представьте, что вы используете следующий запрос, чтобы разделить имя модулей по двоеточию и захватить вторую часть:
var modules = from m in db.Modules
select m.Name.Split(':')[1];
Это вызовет исключение в большинстве провайдеров LINQ: для метода Split нет перевода в SQL. Могут поддерживаться некоторые методы, например, добавление дней к дате, но всё зависит от провайдера.

Методы, которые всё же сработают, могут дать неожиданные результаты…
Рассмотрим следующее выражение LINQ (понятия не имею, зачем это делать на практике, но просто допустим, что надо):
int modules = db.Modules.Sum(a => a.ID);
Если строки в таблице Modules есть, то выражение выдаст сумму значений идентификаторов. Вроде всё правильно. Но что, если применить это выражение к LINQ to Objects? Мы можем сделать это, преобразовав коллекцию модулей в список перед вызовом метода Sum:
int modules = db.Modules.ToList().Sum(a => a.ID);
И ВНЕЗАПНО!… мы получим тот же ответ. Однако, если строк в таблице не будет, то LINQ to Objects вернёт 0, а версия для Entity Framework/LINQ to SQL выдаст исключение InvalidOperationException, сообщающее, что невозможно преобразовать int? в int. Это связано с тем, что вызов SUM в SQL на пустом наборе вместо 0 возвращает NULL. Следовательно, вместо этого он пытается вернуть обнуляемый тип int. Поэтому…

Знайте, когда надо просто использовать старый добрый SQL.
Если вы выполняете чрезвычайно сложный запрос в LINQ, то автоматически сгенерированный SQL запрос может выглядеть как что-то, что съели, выплюнули, снова съели и снова выплюнули. К сожалению, конкретных примеров у меня нет, но, по опыту, использование сложных запросов к нескольким связанным таблицам превращает их поддержку в кошмар. Кроме того, могут появиться проблемы с производительностью, которые будет сложно решить, не имея прямого контроля над сгенерированным SQL. Поэтому либо напишите запрос сразу на SQL, либо доверьте эту работу администратору базы данных (если он у вас есть).

Источник: https://chrisstclair.co.uk/7-dangerous-mistakes-in-c-net-that-are-easy-to-make/
День пятьсот пятьдесят первый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
53. Модульные тесты - пустая трата времени?
Модульные тесты - пустая трата времени: вы всегда будете тратить больше усилий на их поддержку, чем на написание кода.
- Кто-то, в какой-то момент вашей карьеры

Я слышал это десятки раз. Обычно веб-разработчики более склонны так думать, чем их бэкенд-коллеги. И на то есть веская причина: юнит-тестам фронтэнда ещё есть куда расти. В последние годы мне посчастливилось запустить большое количество новых проектов, больших и малых, и, оглядываясь назад, я чувствую, что написание тестов всегда экономило время (или могло бы сэкономить). Но мне потребовалось много времени, чтобы по-настоящему понять их преимущества и изменить свои привычки. Есть много тех, кто до сих пор скептически относится к юнит-тестам, но вот что лично я бы сказал молодому себе: «Забудь про фразу "не хватает времени для написания модульных тестов"».

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

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

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

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

Источник: https://hackernoon.com/are-unit-tests-a-waste-of-your-time-ftw3umv
День пятьсот пятьдесят второй. #ЧтоНовенького
Новые Функции в Visual Studio для Повышения Продуктивности. Начало
Команда Roslyn представляет новые функции для повышения продуктивности в Visual Studio 2019.

1. Автодополнения IntelliSense для форматов DateTime и TimeSpan.
Эта обещает быть чрезвычайно полезным, потому что мы все знаем, как сложно запоминать форматы даты и времени. Поместите курсор в строковый литерал DateTime или TimeSpan и нажмите (Ctrl+Пробел). Вы увидите варианты завершения и объяснение, что означает каждый символ. См. рис.1 ниже.

2. Добавление заголовка файла позволяет легко добавлять заголовки к существующим файлам, проектам и решениям с помощью EditorConfig. Добавьте правило file_header_template в файл .editorconfig и установите нужный текст заголовка. Затем поместите курсор в первую строку любого файла C#. Нажмите Ctrl+., чтобы вызвать меню «Быстрые действия и рефакторинг», и выберите «Добавить заголовок файла» («Add file header»). См. рис.2 ниже.

3. Диалоговое окно изменения сигнатуры метода теперь позволит добавлять параметры. Поместите курсор на сигнатуру метода и Ctrl+., чтобы вызвать меню «Быстрые действия и рефакторинг», и выберите «Изменить сигнатуру» («Change signature»). Откроется окно, где вы можете нажать «Добавить» («Add») для добавления параметра. При этом откроется новое диалоговое окно «Добавить Параметр» («Add Parameter»). См. рис.3 ниже. Оно позволяет задать тип и имя параметра, а также сделать параметр обязательным или необязательным со значением по умолчанию. Кроме того, вы можете задать значение в вызывающем коде (по желанию использовав именованный аргумент для этого значения), либо ввести переменную TODO. Переменная TODO поместит «TODO» в вызывающий код, чтобы вы могли обойти все вызовы метода и передать нужное значение в каждом случае. Для необязательных параметров есть возможность пропустить изменения в вызывающем коде.

Источник: https://devblogs.microsoft.com/dotnet/learn-about-the-latest-net-productivity-features/
День пятьсот пятьдесят третий. #юмор
Примерно так же надо задавать вопрос на Stackoverflow)))
День пятьсот пятьдесят четвёртый. #ЧтоНовенького
Новые Функции в Visual Studio для Повышения Продуктивности. Окончание
Начало

Исправления и рефакторинг кода - это предложения по изменению кода, которые компилятор предоставляет с помощью значков лампочки и отвертки. Чтобы вызвать меню быстрых действий и рефакторинга, нажмите Ctrl+. или Alt+Enter. Команда Roslyn представляет новые возможности исправления и рефакторинга кода в Visual Studio 2019:

- Добавление явного приведения (Add explicit cast). Позволяет добавить оператор явного приведения, если неявное приведение выражения невозможно. См. рис. 1 ниже.

- Упрощение условного выражения (Simplify conditional expression). Делает условные выражения более чёткими и краткими. См. рис. 2 ниже.

- Преобразование в дословную/обычную строку (Convert To Verbatim/Regular String). Позволяет в одно нажатие преобразовать строку из обычной в дословную и наоборот. См. рис. 3 ниже.

- Добавление атрибута «DebuggerDisplay» (Add ‘DebuggerDisplay’ attribute). Предложение появляется, если поместить курсор на имя класса. Позволяет программно закреплять свойства в отладчике кода. Добавляет атрибут отображения в отладчике в начало класса и генерирует автоматический метод, который возвращает ToString(). Метод можно отредактировать, чтобы вернуть значение свойства, которое вы хотите закрепить в отладчике. См. рис. 4 ниже.

- Генерация операторов сравнения (Generate comparison operators). Генерирует шаблонный код с операторами сравнения для типов, реализующих IComparable. См. рис. 5 ниже.

- Генерация операторов IEquatable (Generate Equals(object)). Добавляет реализацию IEquatable, а также операторы равенства и не равенства для структур. См. рис. 6 ниже.

- Генерация конструктора со свойствами (Generate constructor in <QualifiedName> (with properties)). Предложение появляется, если поместить курсор на экземпляр типа. Позволяет добавить в соответствующий тип конструктор нужной сигнатуры и необходимые свойства. См. рис. 7 ниже.

- Исправление случайных присвоений и сравнений (Assign/Compare to '<QualifiedName>.value'). Позволяет исправить операцию присвоения или сравнения, когда имена поля класса и параметра конструктора совпадают. Исправление добавляет “this.” в нужную часть операции. См. рис. 8 ниже.

Источник: https://devblogs.microsoft.com/dotnet/learn-about-the-latest-net-productivity-features/