.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
Передача параметров
Группы параметров по способу передачи в метод:
1. Параметры, передаваемые по значению. Член получает копию фактически переданного аргумента. Если аргумент является значимым типом, копия аргумента помещается в стек. Если аргумент является ссылочным типом, в стек помещается копия ссылки на него. Самые популярные языки CLR, такие как C#, VB.NET и C++, по умолчанию передают параметры по значению.
2. Ref параметры. Член получает ссылку на фактический переданный аргумент. Если аргумент является значимым типом, ссылка на аргумент помещается в стек. Если аргумент является ссылочным типом, в стек помещается ссылка на ссылку. Ref параметры могут использоваться, чтобы позволить члену изменять аргументы, переданные вызывающей стороной.
3. Out параметры. Аналогичны ref параметрам с некоторыми небольшими отличиями. Параметр изначально считается неопределённым и не может быть прочитан в теле члена, пока ему не присвоено какое-либо значение. Кроме того, параметру должно быть присвоено некоторое значение, прежде чем член вернёт управление.

ИЗБЕГАЙТЕ использования параметры out или ref, т.к. это требует опыта работы с указателями, понимания различий между значимыми и ссылочными типами и работы с методами с несколькими возвращаемыми значениями. Кроме того, разработчики фреймворков, проектирующие для широкой аудитории, не должны ожидать от пользователей фреймворка полного понимания различий и принципов работы с out или ref параметрами.
ИЗБЕГАЙТЕ передачи ссылочных типов по ссылке. Есть лишь несколько исключений, например, метод, который используется для обмена ссылками.

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

Источник:
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести тридцать первый. #BestPractices
Советы по разработке членов типов
Разработка параметров. Окончание
Члены с переменным числом параметров
Члены, которые могут принимать переменное число аргументов, создаются путем предоставления параметра-массива. Например, String предоставляет следующий метод:
public class String {
public static string Format(string format, object[] parameters);
}
Пользователь может вызвать метод String.Format следующим образом:
String.Format("Файл {0} не найден в {1}", new object[] { filename, directory });
Добавление ключевого слова params к параметру-массиву изменяет обеспечивает упрощённое создание временного массива:
public class String {
public static string Format(string format, params object[] parameters);
}
Это позволяет пользователю вызывать метод, передавая элементы массива непосредственно в список аргументов:
String.Format("Файл {0} не найден в {1}", filename, directory);
Обратите внимание, что ключевое слово params можно добавить только к последнему параметру.

⚠️ РАССМОТРИТЕ добавление ключевого слова params к параметру-массиву, если вы ожидаете, что конечные пользователи будут передавать массивы с небольшим количеством элементов. Если ожидается, что обычно будет передаваться много элементов, пользователи, вероятно, не будут передавать все эти элементы по одиночке, поэтому ключевое слово params не нужно.
ИЗБЕГАЙТЕ использования params, если вызывающая сторона почти всегда будет иметь данные уже в массиве. Например, члены с параметрами байтового массива почти никогда не будут вызываться путем передачи им отдельных байтов. По этой причине такие параметры в .NET Framework не используют ключевое слово params.
ИЗБЕГАЙТЕ использования params, если массив изменяется членом, принимающим параметр params. Из-за того, что многие компиляторы превращают аргументы params во временный массив, любые изменения в таком массиве будут потеряны.
⚠️ РАССМОТРИТЕ использование ключевого слова params в простой перегрузке, даже если более сложная перегрузка не может его использовать. Решите, оценят ли пользователи наличие массива params в одной перегрузке, даже если он будет не во всех перегрузках.
НЕОБХОДИМО так упорядочить параметры, чтобы можно было использовать ключевое слово params.
⚠️ РАССМОТРИТЕ использование специальных перегрузок для вызовов с небольшим количеством аргументов в чрезвычайно чувствительных к производительности API. Это позволяет избежать создания объектов массива, когда API вызывается с небольшим количеством аргументов.
❗️ ЗАМЕТЬТЕ, что null может быть передан в качестве аргумента params. Вы должны проверить, что массив не равен null перед его обработкой.

Параметры-указатели
В общем случае указатели не должны появляться в публичных API хорошо спроектированной структуры управляемого кода. Большую часть времени указатели должны быть инкапсулированы. Однако в некоторых случаях указатели требуются по причинам совместимости, и использование указателей в таких случаях целесообразно.
НЕОБХОДИМО предоставить альтернативу для любого члена, который принимает аргумент-указатель, потому что указатели не соответствуют CLS.
ИЗБЕГАЙТЕ использования дорогостоящей проверки аргументов-указателей.
НЕОБХОДИМО следовать общим соглашениям по указателям, при разработке элементов с указателями. Например, нет необходимости передавать начальный индекс, потому что простая арифметика указателя может быть использована для достижения того же результата.

Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести тридцать второй. #юмор
День двести тридцать третий. #ЗаметкиНаПолях
Форматирование строк
Статический метод Format класса string принимает составную строку формата, включающую элементы формата, а затем аргументы для замены этих элементов. Например:
string.Format("Привет, {0}.", name);
имеет один элемент формата {0} и заменяет его на значение переменной name. Каждый элемент формата в составной строке формата указывает индекс аргумента, который должен быть отформатирован, но он также может указывать следующие параметры для форматирования значения:
- Выравнивание – указывается минимальная ширина элемента. При этом выравнивание по правому краю обозначается положительным значением, а; выравнивание по левому краю - отрицательным. Указывается через запятую после индекса элемента.
- Строка формата для значения. Чаще всего используется для значений даты и времени или чисел. Например, чтобы отформатировать дату в соответствии с ISO-8601, вы можете использовать строку формата "yyyy-MM-dd". Чтобы отформатировать число в качестве значения валюты, вы можете использовать строку формата "C". Значение строки формата зависит от типа форматируемого значения и указывается после двоеточия.
Например:
decimal price = 95.25m;
string tag = string.Format("Цена: {0,9:C}", price);
Console.Write(tag);
Выведет:
Цена:    $95.25
Формат оставляет 9 символов для значения, выравнивая его по правому краю, а также добавляет символ валюты.
Для вывода в консоль отформатированной строки Console.Write можно использовать непосредственно аналогично string.Format:
Console.Write("Цена: {0,9:C}", price);

Локализация
В общих чертах, локализация - это задача убедиться, что ваш код работает правильно для всех ваших пользователей, независимо от того, где они находятся. В .Net для целей локализации применяется класс CultureInfo. Он содержит настройки культур для языка (вариации языка) или страны: летоисчисление, название дней недели и месяцев, разделители чисел, символ валюты и т.п.
Следующий код выведет в консоль список всех культур, сохранённых на данной машине, и отформатирует дату в соответствии с каждой культурой:
var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
var birthDate = new DateTime(1986, 2, 18);
foreach (var culture in cultures)
{
string text = string.Format(
culture, "{0,-15} {1,12:d}", culture.Name, birthDate);
Console.WriteLine(text);
}
Заметьте, что в отличие от обычных случаев, когда дополнительный необязательный параметр добавляется в конец списка в перегруженной версии метода, культура в методе string.Format указывается первым значением. Это связано с тем, что последним значением указан параметр-массив для аргументов замены (см. https://t.me/NetDeveloperDiary/269).
Чтобы создать объект культуры, нужно использовать метод CultureInfo.GetCultureInfo, передав в него имя культуры. Например, CultureInfo.GetCultureInfo("ru-RU") для русского языка. Кроме того, можно использовать текущую культуру, установленную на машине с помощью статического свойства CultureInfo.CurrentCulture. Это значение используется по умолчанию в методе string.Format. Однако его следует использовать с осторожностью, если предполагается, что приложение будет запускаться на разных компьютерах, т.к. культуры по умолчанию на них могут различаться. Для передачи данных между компьютерами, например, даты в формате ISO-8601 (yyyy-MM-dd), можно использовать инвариантную культуру через статическое свойство CultureInfo.InvariantCulture.

Дословные (verbatim) строки
Символ @, поставленный перед строковым литералом, сообщает конструктору строки, что нужно игнорировать символы перевода строки и символы экранирования. При этом, чтобы использовать двойные кавычки в буквальной строке, надо удвоить символ. Таким образом строку "C:\\\"Program Files\"\\IIS" можно записать как @"C:\""Program Files""\IIS".
Интерполированные строки
В C#6 форматирование строк упрощено с введением интерполированных строк. Специальный знак $ идентифицирует строковый литерал как интерполированную строку. Вместо индекса элемента формата используется выражение интерполяции. Пример выше можно переписать вот так:
string tag = $"Цена: {price,9:C}";
Замечания:
- Чтобы включить в интерполированную строку фигурные скобки, используйте повторение символа "{{" и "}}".
- Чтобы использовать тернарный условный оператор, надо заключить его в скобки: $"{name} is {age} year{(age == 1 ? "" : "s")} old."
- Буквальные интерполированные строки до C#8 обозначались как $@"...", начиная с C#8 порядок символов $ и @ значения не имеет.

Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 9.
День двести тридцать четвёртый. #ЗаметкиНаПолях
Использование nameof
С точки зрения синтаксиса, оператор nameof похож на typeof, за исключением того, что идентификатор в скобках не обязательно должен быть типом. Почему же лучше использовать nameof вместо строковых литералов? Это надёжнее. Если вы сделаете опечатку в строковом литерале, вам нечего укажет на неё, тогда как, если вы сделаете опечатку в имени операнда, вы получите ошибку во время компиляции. Кроме того, компилятор знает, что аргумент nameof связан с элементом или переменной. Если вы переименуете переменную, используя инструмент рефакторинга, имя аргумента тоже изменится. Однако заметьте, что компилятор по-прежнему не сможет определить проблему, если вы ссылаетесь на другой элемент с похожим именем.

Примеры использования
1. Валидация аргументов
При программировании по контракту каждый метод проверяет входящие данные. Это называется предусловиями. Например, далее используется статический метод класса Preconditions для проверки аргумента на null:
public void SomeMethod(string name)
{
Preconditions.CheckNotNull(name, nameof(name));

}
2. Уведомление об изменении калькулируемого свойства
Предположим, что есть класс Rectangle со свойствами Height и Width для чтения и записи и свойство только для чтения Area. Полезно иметь возможность вызвать событие для свойства Area и указать имя свойства безопасным способом:
public class Rectangle : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public double Width
{
get { … }
set
{

RaisePropertyChanged();
RaisePropertyChanged(nameof(Area));
}
}

}
3. Атрибуты
Иногда атрибуты ссылаются на другие члены, чтобы обозначить, как члены связаны друг с другом. Это используется, например, в MVC DataAnnotations, где можно с помощью атрибутов обозначать ограничения, накладываемые на модель, например, требование обязательности поля, если поставлен флажок. NUnit позволяет параметризировать тесты значениями из поля или свойства, используя атрибут TestCaseSource. В Entity Framework достаточно распространено иметь в классе два свойства: одно для внешнего ключа, а другое - для сущности, которую представляет этот ключ:
public class Employee
{
[ForeignKey(nameof(Employer))]
public Guid EmployerId { get; set; }
public Company Employer { get; set; }
}

Особенности использования nameof
1. Указание членов других типов
Стоит помнить, что nameof возвращает только имя члена, без имени класса. Например, nameof(Cultures.AllCultures) вернёт "AllCultures"
2. Обобщения
При использовании typeof, и typeof(List<string>), и typeof(List<>) допустимы и выдают разные результаты. При использовании nameof, во-первых, нельзя использовать тип без аргумента типа nameof(List<>), а во-вторых, и nameof(Action<string>) и nameof(Action<string, string>) вернут просто "Action".
Кроме того, тип параметра не выводится во время выполнения, а используется просто имя типа параметра. То есть для
static string Method<T>() => nameof(T);
И Method<Guid>() и Method<Button>() вернут просто "T".
3. Использование псевдонимов
При использовании псевдонимов nameof также выводит имя псевдонима, а не обозначенного им типа. Следующий код выведет GuidAlias, а не Guid:
using GuidAlias = System.Guid;

Console.WriteLine(nameof(GuidAlias));
4. Предопределённые псевдонимы, массивы и обнуляемые значимые типы
Оператор nameof не может быть использован с предопределёнными псевдонимами (int, char, long, и т.п.), с суффиксом ? у обнуляемых типов или с массивами. То есть все следующие варианты не будут компилироваться:
nameof(float)
nameof(Guid?)
nameof(String[])

Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 9.
👍1
День двести тридцать пятый. #ЗаметкиНаПолях
Использование using static
Директива using static служит для упрощённого импорта следующих членов классов:
1. Статические поля, свойства и методы. Канонический пример – использование класса Math:
using static System.Math;

// перевод градусов в радианы, используя Math.PI
double radians = degrees * PI / 180;
// площадь треугольника через Math.Sin
double area = 1/2 * sideA * sideB * Sin(angle);
2. Значения перечислений. Это полезно, если в коде много раз используются значения перечисления. В примере ниже перебираются значения перечисления HttpStatusCode. Добавив using static, в операторе switch можно опускать имя перечисления:
using static System.Net.HttpStatusCode;
...
switch (response.StatusCode)
{
case OK: …
case TemporaryRedirect: …
case Redirect: …
case RedirectMethod: …
case NotFound: …
default: …
}
3. Вложенные типы.
Вложенные типы чаще используются в сгенерированном коде. Однако, если вы ими пользуетесь, возможность напрямую их импортировать может упростить написание кода.

Методы расширения и using static
Два важных момента взаимодействия методов расширения и директивы using static:
1. Методы расширения из одного типа могут быть импортированы с использованием директивы using static с этим типом без импорта каких-либо методов расширения из остальной части данного пространства имен. Например, класс System.Linq.Queryable содержит методы расширения для деревьев выражений IQueryable<T>, а класс System.Linq.Enumerable содержит методы расширения для делегатов, принимающих IEnumerable<T>. Поскольку IQueryable<T> наследуется от IEnumerable<T>, используя обычную директиву using для System.Linq, вы можете использовать методы расширения, принимающие делегаты в IQueryable<T>, хотя обычно этого не требуется. Далее показано, как использование статической директивы только для System.Linq.Queryable приводит к тому, что методы расширения из System.Linq.Enumerable не подключаются:
using System.Linq.Expressions;
using static System.Linq.Queryable;
...
var query = new[] { "a", "bc", "d" }.AsQueryable();
Expression<Func<string, bool>> expr = x => x.Length > 1;
Func<string, bool> del = x => x.Length > 1;
var valid = query.Where(expr);
var invalid = query.Where(del);
Последняя строка приводит к ошибке компиляции, поскольку методу Where передаётся делегат, а не дерево выражений. Таким образом, если у вас в проекте есть файл с методами расширения для различных типов проекта, можно разделить методы расширения, относящиеся к разным типам, на разные классы расширений и импортировать каждый класс по отдельности с помощью using static.
2. Методы расширения, импортированные из типа, нельзя вызывать, как статический методы (как выше вызывался метод Sin класса Math). Вместо этого вы должны вызывать их, как если бы они были экземплярами методов расширяемого типа. Например, метод расширения Enumerable.Count:
using System.Collections.Generic;
using static System.Linq.Enumerable;

IEnumerable<string> strings = new[] { "a", "b", "c" };
int valid = strings.Count();
int invalid = Count(strings);
Последняя строка приведёт к ошибке компиляции.

Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 10.
День двести тридцать шестой. #Оффтоп
Как стать продуктивнее. Начало
В разработке ПО даже один разработчик может иметь большое значение. Вот почему найти отличных инженеров так сложно, а зарплаты программистов стремительно растут. Высокопроизводительный разработчик ПО - невероятный актив в команде. Компания готова платить им самую высокую зарплату, а конкуренция за них самая жёсткая. Эффективный высокопроизводительный разработчик - профессионал, который выполняет работу быстро и эффективно. Тот, кто обладает невероятной производительностью и высоким качеством. Кто-то, про кого вы просто не можете понять, как они могут так много делать.
Эти советы помогут значительно оптимизировать свою производительность, уменьшить стресс и быть довольным результатами.
1. Настройте мышление на высокую эффективность
Прежде всего, самое главное – захотеть стать эффективным и высокопроизводительным разработчиком. Высокопроизводительный разработчик приходит к себе на работу с намерением добиться как можно большего в этот день. Это главная директива, которую нужно помнить во время работы. Высокая эффективность приносит много пользы. С точки зрения карьеры, продуктивный разработчик - огромный актив. Вы будете получать больше прибавок, бонусов, повышений по службе и хороших отзывов. Кроме того, высокая производительность в какой-то момент превращается в игру. Выполнение заданий - это весело и просто. Еще одно преимущество - опыт работы. Если вы выполняете вдвое больше заданий в течение одного дня, вы также удваиваете свой опыт работы.
2. Пишите список целей на день
Один из наиболее эффективных инструментов повышения производительности - это простой список дел с задачами на день. Запишите в начале дня, что вы хотите сделать. Затем, по мере выполнения вычёркивайте элементы из списка. Это очень просто, но эффект потрясающий. Простое вычеркивание задач из списка дел очень радует. На самом деле это встроено в наш мозг. Когда мы чего-то добиваемся, наше тело вырабатывает дофамин, который немедленно доставляет нам удовольствие. Это, в свою очередь, заставляет нас хотеть повторить это удовольствие и сделать ещё больше работы. Другими словами - списки задач делают вас более продуктивным, а работу более приятной.

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

Источник:
https://michaelscodingspot.com
День двести тридцать седьмой. #Оффтоп
Как стать продуктивнее. Продолжение
3. Планируйте подход к текущей задаче
Прежде чем писать код, отлаживать или даже касаться клавиатуры, подумайте. Как вы собираетесь решать свою задачу? Какие классы вы собираетесь создать? Где вы собираетесь устанавливать контрольные точки? С какими препятствиями вы можете столкнуться?
Вы должны задать себе все эти вопросы в самую первую очередь. Как только вы создадите план решения задачи в своей голове (или даже лучше, на бумаге), вы сможете точно спланировать свои шаги. Это приводит к организованному и эффективному рабочему процессу. Он сфокусирует вас на вашей задаче и предотвратит ненужные приключения, которые не принесут никакой пользы. В результате ваша производительность будет стремительно расти.
4. Сохраняйте спокойствие
Программирование может быть очень увлекательным, но также может быть сложным и разочаровывающим. Есть такие задачи, которые вы даже не будете знать, как начать решать. Иногда вы оцениваете, что задача будет решена за 2 часа, а в итоге решение занимает 2 дня. Или же вы можете столкнуться с жёсткими дедлайнами и переключением между задачами.
Программирование может быть действительно напряжённым, но решение простое - сохраняйте спокойствие. Злоба и разочарование затуманивают ваш разум, и в итоге вы потратите ещё больше времени на выполнение задачи или наделаете ошибок. Сохранять спокойствие легче сказать, чем сделать. У каждого свои методы для этого. Мне хватает просто помнить, что я должен быть спокоен.
5. Делайте перерывы и работайте в течение заранее определенных периодов
Есть несколько причин, почему перерывы в работе помогают повысить производительность. Для меня это сводится к двум причинам.
Когда я знаю, что собираюсь работать в течение определенного периода времени, мне легче сосредоточиться на своей задаче. Я работаю по методу «Помидора», где вы работаете 25 минут и делаете перерыв на 5 минут. Поэтому, пока я провожу 25 минут, я не чувствую желания проверить фейсбук, ответить на сообщения или переключиться на другую задачу. Я полностью сосредоточен на непосредственной задаче в эти 25 минут.
Перерывы помогают мне думать и разбирать проблемы. Вероятно, решения проблем, приходят мне в голову чаще в ванной, чем перед компьютером. Наверное, есть какая-то магия в том, чтобы встать, сделать небольшой перерыв и отвлечься на другие темы, и она работает.

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

Источник:
https://michaelscodingspot.com
День двести тридцать восьмой. #Оффтоп
Как стать продуктивнее. Продолжение
6. Начинайте с самой трудной части
Во многих задачах у вас может быть какое-то технологически узкое место, которое вы не знаете, как реализовать. Всё остальное может быть простым, то, что вы делали сто раз, но вот с этим вы не знаете, как справиться.
Мой совет - начать с самого сложного. Одна из причин заключается в том, что, как только вы решите это, вы будете намного увереннее в остальном. Другая причина в том, что, работая с этой частью, вы можете понять, что задача не может быть выполнена так, как вы планировали, и вы сэкономите много времени.

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

8. Просите помощи… но не слишком часто
Никто не может отрицать, что обращение за помощью эффективно. Если вы начинаете работать в новом месте, работаете над незнакомым кодом или просто ищете совета, это чрезвычайно полезно.
Но с такой помощью есть проблема в том, что, когда кто-то что-то вам объясняет, вы понимаете меньше, чем если бы вы сами до этого додумались. Когда вы расшифруете код самостоятельно, вы получите глубокое его понимание. Все логические части сойдутся воедино, и вы сможете решить любую проблему в этом коде позже. Когда кто-то вам это объяснит, вы поймете какую-то часть уравнения, но остальное останется загадкой, пока вы в следующий раз не обратитесь за помощью.
Поэтому важно найти баланс между обращением за помощью и самостоятельным решением. С одной стороны, вы можете застрять на долгое время без посторонней помощи. С другой стороны, обращение за помощью каждый раз приведет к тому, что вы получите наименьший опыт. Мой совет - постарайтесь хоть что-нибудь выяснить самостоятельно, прежде чем просить о помощи. Таким образом, даже если вы в конечном итоге попросите о помощи, вы намного лучше поймете, что вам ответят.

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

Источник:
https://michaelscodingspot.com
День двести тридцать девятый. #Оффтоп
Как стать продуктивнее. Окончание
9. Изучите суть вашей технологии
В какой бы компании вы ни работали, вы, вероятно, используете набор технологий. Это может быть язык программирования, несколько фреймворков и несколько инструментов. Если это то, чем вы постоянно пользуетесь, то стоит углубленно изучить суть вашей технологии.
Имеется в виду помимо того опыта, который вы набираете во время работы. Пройдите какой-нибудь курс, чтобы изучить технологию. Это может быть онлайн-курс, видеоуроки, книга, документация или что-то еще. Да, это займет много времени, но рассматривайте это как долгосрочное вложение.

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

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

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

Источник: https://michaelscodingspot.com
День двести сороковой. #юмор
Как выглядят избыточные комментарии в коде.
День двести сорок первый. #ЗаметкиНаПолях
Tracepoints: отладка без помех. Начало
Вы используете отладочный вывод? Давайте будем честными, мы все когда-либо делали это. Будь то Debug.WriteLine(), console.log(), print() и т. д. Вывод данных в консоль - обычная практика. А вы когда-нибудь забывали удалить отладочный вывод из живого кода? И вдруг то, что кажется простым и приятным подходом к отладке, превращается в большую работу по очистке кода. Кроме того, если отладочный вывод используется в нескольких местах, его периодически приходится удалять, чтобы не загромождать консоль.
Если это так, то Tracepoints (точки трассировки) - отличный инструмент, который вы можете использовать в Visual Studio. Эта функция позволяет регистрировать нужную информацию без изменения кода и инициализируется аналогично точкам останова. Когда вы закончите отладку, просто нажмите на точку трассировки, чтобы удалить ее.
Допустим, мы хотим посмотреть значение counter для каждой итерации цикла for (см. картинку ниже). Одним из решений является использование оператора отладки, такого как Debug.WriteLine(counter). В то время как это, безусловно, решает эту простую задачу, нам потребовалось изменить наш код а позже потребуется удалить эту строку, чтобы она не попала в продакшн.
С помощью точек трассировки вы можете делать это, не изменяя код. Обратите внимание, что, когда вы добавляете сообщение в поле «Show a message in the Output window field» в меню Actions (см. картинку), вы никак не изменяете свой исходный код. Это позволяет вам получать необходимую информацию в окне вывода Visual Studio, без ущерба для читабельности вашего кода. Кроме того, когда вы закончите отладку, просто нажмите на точку трассировки один раз, чтобы удалить её. Но даже если вы забыли это сделать, не стоит беспокоиться о постороннем выводе, потому что точки трассировки существуют только локально на вашем компьютере.

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

Источник:
https://devblogs.microsoft.com/visualstudio/tracepoints/
День двести сорок второй. #ЗаметкиНаПолях
Tracepoints: отладка без помех. Окончание
Допустим, мы хотим выводить только чётные значения счётчика или значения только во время определённой итерации цикла. В блоке Conditions мы можем добавлять условия аналогично условным точкам останова.
Есть три типа условий:
1. Условное выражение (Conditional Expression): сообщение отображается только при определенных условиях, например, counter == 5.
2. Счетчик выполнений (Hit Count): это условие позволяет вам выводить данные только после того, как эта строка кода выполнится заданное количество раз.
3. Фильтр (Filter): точка трассировки будет активирована только на указанных устройствах, процессах или потоках.
Добавление этих условий не изменяет ваш исходный код и, в отличие от точек останова, не останавливает программу и не потребует от вас многократного перехода из программы в отладку и обратно (если установлен флажок «Continue code» в блоке Actions).

Советы
1. Сообщения трассировки отправляются в окно Output. Их легко потерять среди множества других вещей, которые отправляются в это же окно. Если щелкнуть правой кнопкой мыши в окне Output, вы можете отключать типы сообщений, такие как сообщения об исключениях, сообщения о выходе из процесса и т. д. Так вам будет легче сосредоточиться на выводе вашей точки трассировки.
2. Если ваша текущая задача требует наличия всех сообщений, ещё один способ облегчить поиск выходных данных - это поставить уникальный префикс сообщения перед выводом данных, например, MyOutput: {counter}. При отладке вы можете использовать команду поиска Ctrl+F в окне Output, чтобы найти префикс, который вы установили, и окно отобразит для вас нужный вывод.
3. Чтобы временно отключить точку трассировки без её удаления, щёлкните по ней, удерживая Shift.
4. Для одновременного просмотра, отключения или удаления всех точек трассировки и точек останова в текущем файле перейдите в Debug -> Windows -> Breakpoints, чтобы открыть окно точек останова.

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

Дополнительная информация про точки трассировки находится в документации по Visual Studio: https://docs.microsoft.com/en-us/visualstudio/debugger/using-tracepoints?view=vs-2019

Источник: https://devblogs.microsoft.com/visualstudio/tracepoints/
День двести сорок третий. #BestPractices
Разработка для Расширяемости
Одним из важных аспектов проектирования приложения является тщательное планирование его расширяемости. Для этого необходимо понимать затраты и выгоды, связанные с различными механизмами расширяемости.
Есть много способов обеспечить расширяемость приложения. Они варьируются от менее мощных, но менее дорогих до очень мощных, но дорогих. Для любого заданного требования расширяемости вы должны выбирать наименее дорогостоящий механизм, соответствующий требованиям.

Незапечатанные классы
Запечатанные (sealed) классы не могут быть унаследованы, и они препятствуют расширяемости. Напротив, классы, которые могут быть унаследованы, называются незапечатанными классами.
⚠️ РАССМОТРИТЕ использование открытых классов без добавления виртуальных или защищенных членов в качестве способа обеспечить недорогую, но очень ценную расширяемость.
Разработчики часто хотят наследовать от незапечатанных классов, чтобы добавить вспомогательные элементы, такие как пользовательские конструкторы, новые методы или перегрузки методов. Например, System.Messaging.MessageQueue является незапечатанным и, таким образом, позволяет пользователям создавать настраиваемые очереди по умолчанию для определённого пути очереди или добавлять настраиваемые методы, которые упрощают API для конкретных сценариев.
Классы по умолчанию незапечатаны в большинстве языков программирования, и это также рекомендованное поведение по умолчанию для большинства классов. Расширяемость, предоставляемая незапечатанными типами, высоко ценится пользователями фреймворков и довольно недорогая для обеспечения из-за относительно низких затрат на тестирование, связанных с незапечатанными типами.

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

Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести сорок четвёртый. #BestPractices
Разработка для Расширяемости
Защищённые Члены
Защищенные (protected) члены доступны в пределах своего класса или из экземпляров производного класса. Защищённые члены сами по себе не обеспечивают расширяемости, однако они усиливают расширяемость через подклассы. Их можно использовать для предоставления расширенных возможностей без ненужного усложнения основного публичного интерфейса.
Разработчики фреймворков должны быть осторожны с защищёнными членами, потому что название «защищённый» может дать ложное чувство безопасности. Кто угодно может создать подкласс незапечатанного класса и получить доступ к защищённым членам, поэтому все методы защитного программирования, которые используются для открытых членов, применимы к защищённым членам.
⚠️ РАССМОТРИТЕ использование защищённых членов для расширенной настройки типов.
❗️ НЕОБХОДИМО относиться к защищённым членам в открытых классах как к открытым при анализе безопасности, совместимости или документировании. Кто угодно может наследовать от класса и получить доступ к защищённым членам.

Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести сорок пятый. #BestPractices
Разработка для Расширяемости
События и Функции обратного вызова
Функции обратного вызова - это точки расширения, которые позволяют платформе вызывать пользовательский код через делегата. Эти делегаты обычно передаются в структуру через параметр метода.
События - это особый случай обратных вызовов, который поддерживает удобный и согласованный синтаксис для предоставления делегата (обработчик события). Кроме того, разработчики помогают в этом, предоставляя API на основе событий.
⚠️ РАССМОТРИТЕ использование обратных вызовов, чтобы позволить пользователям выполнять свой код на определённых этапах работы фреймворка.
⚠️ РАССМОТРИТЕ использование событий, чтобы позволить пользователям настраивать поведение фреймворка без необходимости понимания объектно-ориентированного проектирования.
ИСПОЛЬЗУЙТЕ события вместо обратных вызовов, где это возможно, потому что они знакомы более широкому кругу разработчиков.
ИЗБЕГАЙТЕ использования обратных вызовов в чувствительных к производительности API.
ИСПОЛЬЗУЙТЕ типы Func<…>, Action<…> или Expression<…> вместо пользовательских типов делегатов при определении API с обратными вызовами. Func<…> и Action<…> представляют обобщённые делегаты. Expression<…> представляет определения функций, которые могут быть скомпилированы и впоследствии вызваны во время выполнения, но также могут быть сериализованы и переданы удаленным процессам.
ИСПОЛЬЗУЙТЕ замеры производительности, чтобы понимать последствия использования Expression<…> вместо делегатов Func<…> и Action<…>. Типы Expression<…> в большинстве случаев логически эквивалентны делегатам Func<…> и Action<…>. Основное различие между ними заключается в том, что делегаты предназначены для использования в сценариях локальных процессов, а выражения предназначены для случаев, когда необходимо произвести оценку выражения в удаленном процессе или машине.
❗️ ЗАМЕТЬТЕ, что, вызывая делегата, вы выполняете произвольный код, что может иметь последствия для безопасности, корректности и совместимости.

Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести сорок шестой. #BestPractices
Разработка для Расширяемости
Виртуальные Члены
Виртуальные члены могут быть переопределены, тем самым изменяя поведение подкласса. Они очень похожи на обратные вызовы с точки зрения расширяемости, которую они предоставляют, но они лучше с точки зрения производительности и потребления памяти. Кроме того, виртуальные члены более естественны в сценариях, которые требуют создания особого вида существующего типа (специализация). Виртуальные члены работают лучше, чем обратные вызовы и события, но хуже, чем невиртуальные методы.
Основным недостатком виртуальных членов является то, что поведение виртуального члена может быть изменено только во время компиляции. Поведение же метода обратного вызова может быть изменено во время выполнения.
Виртуальные члены, также как и обратные вызовы, являются дорогостоящими для разработки, тестирования и обслуживания, поскольку любой вызов виртуального члена может быть переопределен непредсказуемым образом и может выполнить произвольный код. Кроме того, обычно требуется больше усилий для чёткого определения контракта виртуальных членов, поэтому стоимость их разработки и документирования выше.

ИЗБЕГАЙТЕ создания виртуальных членов, если у вас нет веских причин для этого, и вы не просчитали все расходы, связанные с проектированием, тестированием и обслуживанием виртуальных членов. Виртуальные члены менее защищены от изменений, которые могут быть внесены в них без нарушения совместимости. Кроме того, они медленнее, чем невиртуальные, в основном потому, что компилятор не может оптимизировать код, встроив вызов виртуального члена.
ИСПОЛЬЗУЙТЕ расширяемость только для тех членов, которым она абсолютно необходима.
ИСПОЛЬЗУЙТЕ защищённый (protected) модификатор доступа для виртуальных членов. Открытые члены должны обеспечивать расширяемость (если она требуется), вызывая защищённый виртуальный член. Открытые члены класса должны предоставлять правильный набор функциональных возможностей для прямых потребителей этого класса. Виртуальные члены предназначены для переопределения в подклассах, и защищённый доступ к ним является отличным способом для предоставления потребителям типа возможности для расширения.

Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
День двести сорок седьмой. #BestPractices
Разработка для Расширяемости
Абстракции (Абстрактные типы и интерфейсы)
Абстракция - это тип, который описывает контракт, но не обеспечивает полную реализацию этого контракта. Абстракции обычно реализуются в виде абстрактных классов или интерфейсов и содержат чёткую справочную документацию, описывающую необходимую семантику типов, реализующих контракт. Некоторые из наиболее важных абстракций в .NET Framework включают Stream, IEnumerable<T> и Object.
Вы можете расширять фреймворки, реализовав конкретный тип, который поддерживает контракт абстракции, и используя этот конкретный тип с API-интерфейсами фреймворка, работающими с использованием абстракции.
Содержательную и полезную абстракцию, способную выдержать испытание временем, очень сложно спроектировать. Основная трудность - создать правильный набор членов, не больше и не меньше. Если абстракция имеет слишком много членов, она становится трудной или даже невозможной для реализации. Если у неё слишком мало членов для обещанной функциональности, она становится бесполезной во многих нужных сценариях.
Слишком большое количество абстракций в фреймворке также негативно влияет на удобство использования фреймворка. Часто довольно трудно понять абстракцию, не понимая, как она вписывается в общую картину конкретных реализаций и API, работающих с абстракцией. Кроме того, названия абстракций и их члены обязательно являются слишком общими, что часто делает их непонятными без предварительного глубокого разбора контекста их использования.
Однако абстракции обеспечивают чрезвычайно мощную расширяемость, которую другие механизмы расширяемости часто не могут предоставить. Они лежат в основе многих архитектурных шаблонов, таких как подключаемые модули, инверсия управления (IoC), конвейеры и т. д. Они также чрезвычайно важны для тестируемости фреймворков. Хорошие абстракции позволяют избавиться от тяжелых зависимостей для проведения модульного тестирования. Таким образом абстракции отвечают за богатство современных объектно-ориентированных структур.

ИЗБЕГАЙТЕ предоставления абстракций, если они не протестированы путем разработки нескольких конкретных реализаций и API, использующих эти абстракции.
НЕОБХОДИМО выбрать между абстрактным классом и интерфейсом при разработке абстракции.
⚠️ РАССМОТРИТЕ предоставление справочных тестов для конкретных реализаций абстракций. Такие тесты должны позволять пользователям проверять, правильно ли их реализации реализуют контракт.

Источник: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/