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

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День пятидесятый. #ЗаметкиНаПолях
Управление цепочками делегатов
В C# можно создавать и управлять цепочками делегатов при помощи операторов += и -=. Цепочку делегатов можно вызвать так же, как и единичный делегат. При этом будут вызваны все делегаты цепочки по очереди. Это достаточно удобно и подходит для большинства сценариев. Однако у этого метода есть ряд ограничений. Например, сохраняется только последнее из возвращаемых значений, возвращаемых методами. Получить остальные значения нельзя. Кроме того, если один из делегатов в цепочке выбрасывает исключение, работа цепочки останавливается.
В качестве альтернативы можно использовать метод GetInvokationList класса MulticastDelegate. Он возвращает массив ссылок на делегаты в цепочке. Следующий код безопасно выполняет делегаты из цепочки и сохраняет их возвращаемые значения:
private delegate string MyDelegate();

private static string Method1() => "Method1";
private static string Method2() => throw new Exception("Exception");
private static string Method3() => "Method3";

static void Main(string[] args)
{
MyDelegate getResult = null;
getResult += new MyDelegate(Method1);
getResult += new MyDelegate(Method2);
getResult += new MyDelegate(Method3);

Console.WriteLine(GetAllResults(getResult));
}

private static string GetAllResults(MyDelegate result)
{
if (result == null) return null;

var report = new StringBuilder();
var delegates = result.GetInvocationList();
foreach (MyDelegate del in delegates)
{
try
{
//пытаемся выполнить метод, сохраняя его результат
report.AppendFormat("{0}\n", del());
}
catch (Exception ex)
{
//обрабатываем ошибки метода
//здесь component – класс владелец метода
var component = del.Target;
report.AppendFormat(
" Ошибка при получении результата из метода {0}{1}: {2}\n",
((component == null) ? "" : component.GetType() + "."),
del.Method.Name,
ex.Message);
}
}

return report.ToString();
}

Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 17.
День пятьдесят первый. #TipsAndTricks
Обучение IntelliCode
Недавно я рассказывал, как IntelliCode помогает вам писать код, выбирая наиболее подходящие подсказки на основе тысяч часто используемых библиотек в репозиториях GitHub. Вместо поиска и прокрутки отсортированного списка методов и свойств, вы получаете наиболее вероятные подсказки на основе вашего контекста программы.
Но что, если вы хотите получать такие подсказки на основе вашего набора библиотек? В C# вы можете позволить IntelliCode анализировать ваш собственный код и делиться результатами анализа внутри вашей команды. Установить зависимость IntelliCode от вашего кода, проанализировать его и поделиться результатами анализа с коллегами можно в течение нескольких минут. Это можно сделать в 3 простых шага:
1. Убедитесь, что у вас установлено расширение IntelliCode для
Visual Studio.
2. Создайте вашу модель кодовой базы, содержащую хорошие примеры использования желаемых библиотек классов. Помните, что качество подсказок, предлагаемых IntelliCode напрямую зависит от качества примеров, которые вы предоставите.
3. Поделитесь моделью с вашими коллегами, чтобы они смогли использовать рекомендации. Если вам потребуется обновить модель, например, после внесения существенных изменений в код, ваша команда автоматически получит последние изменения.
Подробности тут: https://docs.microsoft.com/en-us/visualstudio/intellicode/faq

Источник: https://devblogs.microsoft.com/visualstudio/code-more-scroll-less-with-visual-studio-intellicode/?utm_source=vs_developer_news&utm_medium=referral
День пятьдесят второй.
Сертификат Microsoft. Шаг 2
Поискал информацию о сдаче экзамена 70-483 «Programming in C#». Интересен был опыт людей, прошедших через это. На удивление статей не так много:
- Хабр https://habr.com/ru/post/245067/ (пятилетней давности).
- Блог на BlogSpot http://sonyks2007.blogspot.com/2014/02/mcp.html (пятилетней давности).
- Блог Андрея Акиньшина https://aakinshin.net/ru/posts/ms-mcp/ (пятилетней давности).
- Блог Дмитрия Маслова http://dmaslov.net/2018/09/06/exam-70-483/ (прошлогодний).
Остальное откровенный шлак, нисколько не полезный.

Что хочется отметить:
1. Авторы не раскрывают вопросов от слова совсем. На это ты подписываешь соглашение о неразглашении перед экзаменом.
2. Темы варьируются. Например, интересно было узнать, что в экзамен входят вопросы по шифрованию данных и управлению сборками. Не помню этих тем в списке на оф. сайте экзамена.
3. Книги по подготовке:
- Wouter de Kort, Exam Ref 70-483: Programming in C#
- Tiberiu Covaci, MCSD Certification Toolkit (Exam 70-483): Programming in C# (Wrox Programmer to Programmer)
Несколько человек написали, что не стоят своих денег, и если первая ещё более менее, то вторая содержит дикое количество ошибок и на неё вообще не стоит тратить время.
4. Варианты вопросов всё-таки есть вот на этом сайте: https://exambraindumps.com/70-483.html Там же можно сдать пробный экзамен. Не знаю, насколько легально это там размещено. Вопросы, говорят, что тоже не без ошибок. Посмотрим. Нужно выделить 1,5 часа на пробный тест.
Продолжаем подготовку…

PS: Хотел узнать, где поблизости можно пройти экзамен, т.к. из авторов один сдавал в Киеве, другой в Екатеринбурге, но кнопка "Запланировать экзамен" на сайте экзамена почему-то ведёт на пустую страницу.
День пятьдесят третий. #TipsAndTricks
Условие Прерывания на Исключении
В Visual Studio, вы можете использовать окно Exception Settings (Debug -> Windows -> Exception Settings) для управления исключениями: на каких исключениях среда должна прерываться, а также добавлять и удалять исключения. В Visual Studio 2017 появились дополнительные возможности управления. Вы можете установить условие прерывания.
Перейдите в окно Exception Settings и выберите типы исключений, для которых вы хотите задать условие. Выберите Редактировать Условие (Edit Condition). Здесь введите название модулей, в которых вы хотите, чтобы выполнение прерывалось. В настоящее время доступно только условие по имени модуля. Таким образом, при выполнении кода Visual Studio будет выбрасывать исключение CLR только при удовлетворении условию. Это полезно, когда вы хотите исключить срабатывание на известных ошибках какой-либо библиотеки (сторонней или находящейся в разработке).

Источник: https://dailydotnettips.com/
День пятьдесят четвёртый. #ЗаметкиНаПолях
Атрибуты. Начало
Атрибуты предоставляют мощный способ связывания метаданных с кодом.
Свойства атрибутов:
- Добавление метаданных в вашу программу, то есть информации о типах, определённых в программе. Все сборки .NET содержат набор метаданных, описывающих типы и члены типов, определённые в сборке. Можно добавлять свои атрибуты, создавая классы-наследники System.Attribute.
- Вы можете применить один или несколько атрибутов ко всей сборке, модулю или более мелким элементам программы, таким как классы и свойства.
- Атрибуты могут принимать аргументы так же, как методы и свойства.
- Ваша программа может получать доступ к своим метаданным или к метаданным других программ, используя рефлексию.

Использование атрибутов
Атрибуты могут применяться к практически любому объявлению: сборкам, модулям, типам, полям, возвращаемым значениям, методам, параметрам, свойствам, событиям, а также к полям и методам, создаваемым компилятором. Атрибуты указываются в квадратных скобках ([]) над объявлением сущности, к которой они применяются.
В этом примере атрибут SerializableAttribute используется для объявления характеристики класса:
[Serializable]
public class SampleClass
{
// Объекты этого типа могут быть сериализованы.
}
По соглашению все имена атрибутов заканчиваются словом "Attribute", чтобы отделять их от других элементов библиотек .NET. Но его можно опускать при использовании атрибутов в коде. Например, [DllImport] эквивалентно [DllImportAttribute], но настоящее имя класса атрибута в библиотеке классов .NET Framework - DllImportAttribute.
Параметры атрибутов
Многие атрибуты имеют параметры, которые могут быть позиционными (неименованными) или именованными. Позиционные параметры обязаны указываться в определённом порядке и не могут быть опущены. Именованные параметры не обязательны и могут указываться в любом порядке. Позиционные параметры указываются первыми. Следующие три атрибута эквивалентны:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
Первый параметр (имя DLL) позиционный и всегда идёт первым. Другие параметры именованные, оба по умолчанию имеют значение false, поэтому могут быть опущены. Позиционные параметры – это параметры конструктора атрибута, именованные соответствуют свойствам или полям атрибута.

Целевые объекты атрибутов
Целевой объект атрибута – это сущность, к которой применяется атрибут. По умолчанию атрибут применяется к элементу, которому он предшествует. Но вы можете явно определить, например, относится ли атрибут к методу, его параметру, либо к возвращаемому значению.
В следующем примере атрибуты применяются к сборке и модулю:
using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]
А в этом примере атрибуты применяются к методу и к возвращаемому значению метода:
// по умолчанию: применяется к методу
[ValidatedContract]
int Method1() { return 0; }

// применяется к методу
[method: ValidatedContract]
int Method2() { return 0; }

// применяется к возвращаемому значению
[return: ValidatedContract]
int Method3() { return 0; }
Замечание. Некоторые целевые объекты обязательны для указания в атрибуте для разрешения конфликтов между неоднозначными целевыми объектами атрибута:
- assembly – сборка,
- module – модуль,
- return – возвращаемое значение,
- field (для полей, созданных компилятором),
- method (для методов, созданных компилятором).
Примеры использования атрибутов
Далее приведены несколько наиболее частых примеров использования атрибутов в коде:
- Атрибутом WebMethod в веб-сервисах помечаются методы, которые можно вызывать по протоколу SOAP.
- Описание маршалинга параметров метода при взаимодействии с машинным кодом.
- Описание свойств COM для классов, методов и интерфейсов.
- Вызов неуправляемого кода с помощью атрибута
DllImport.
- Описание названия, версии, описания или торговой марки вашей сборки.
- Описание сериализуемых членов класса.
- Описание соответствия членов класса узлам XML при XML-сериализации.
- Описание требований безопасности для методов.
- Управление оптимизацией JIT-компилятора.
- Получение информации об объекте, вызвавшем метод.

Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 18.
-
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/
День пятьдесят пятый. #TipsAndTricks
Улучшите читаемость чисел, используя Разделитель Цифр в C# 7
Иногда в коде приходится использовать литеральные значения чисел. Иногда они маленькие, а иногда достаточно большие. В случае с маленькими числами проблем нет, но длинные числа иногда тяжело читать. C# 7.0 позволяет использовать разделитель ‘_’ в литералах для улучшения читаемости вашего кода. Разделитель никак не влияет на число, вы можете использовать такое число так же, как любую другую целочисленную переменную. Разделители также могут применяться в двоичных и шестнадцатеричных выражениях чисел. Начиная с версии 7.2 можно отделять также части '0b' и '0x':
var number = 123_456_789;
var binary = 0b111_1110_0011;
var binary_7_2 = 0b_111_1110_0011; // C# 7.2+
var hex = 0x7_e3;
var hex_7_2 = 0x_7e3; // C# 7.2+
День пятьдесят шестой. #ЗаметкиНаПолях
Общие атрибуты
1. Глобальные атрибуты
Применяются к сборке или модулю в целом. Например, AssemblyVersion используется для указания версии сборки:
[assembly: AssemblyVersion("1.0.0.0")]
В коде глобальные атрибуты располагаются после директив высшего уровня и перед любыми объявлениями классов, модулей или пространств имён. В проектах C# они помещаются в файл AssemblyInfo.cs.
Различают три категории атрибутов сборки:
- атрибуты идентификации сборки: обязательные атрибуты для сборки (AssemblyName, AssemblyVersion, AssemblyCulture, AssemblyFlags),
- информационные атрибуты: дополнительная информация о сборке (AssemblyProduct, AssemblyTrademark, AssemblyInformationalVersion, AssemblyCompany, AssemblyCopyright, AssemblyFileVersion, CLSCompliant)
- атрибуты манифеста сборки (AssemblyTitle, AssemblyDescription, AssemblyConfiguration, AssemblyDefaultAlias).
2. Атрибут Obsolete
Обозначает элементы программы, не рекомендуемые для дальнейшего использования. Выдаёт предупреждение компилятора или ошибку компиляции в зависимости от настройки:
[System.Obsolete("use class B")]  
class A
{
public void Method() { }
}
class B
{
[System.Obsolete("use NewMethod", true)]
public void OldMethod() { }
public void NewMethod() { }
}
В этом примере использование класса A приведёт к предупреждению компилятора, а использование метода OldMethod класса B к ошибке, т.к. второй параметр конструктора атрибута (error) установлен в true. Первый строковый параметр (message) используется как сообщение компилятора. Он не обязательный, но его рекомендуется задавать.
3. Условный атрибут
Условный атрибут ставит выполнение метода в зависимость от идентификатора препроцессора, определяемого в коде следующим образом:
#define CONDITION1
Чаще всего он используется с идентификатором DEBUG, для включения функций трассировки и ведения журнала для отладочных сборок (но не в релизе):
[Conditional("DEBUG")]  
static void DebugMethod() { /*…*/ }
Атрибут определяет, вызывается или нет метод, помеченный им. Если идентификатор не определён, метод не вызывается. Условный метод должен быть определён в классе или структуре и не должен возвращать значений.
Условные атрибуты можно совмещать. Тогда метод будет исполнен, если хотя бы один из идентификаторов определён:
[Conditional("A"), Conditional("B")]  
static void DoIfAorB() { /*…*/ }
4. Атрибуты Caller Info
Используя атрибуты Caller Info, вы можете получить информацию об объекте, вызвавшем метод: имя свойства или метода, путь к исходному файлу и номер строки в файле. Атрибуты указываются для необязательных параметров метода, которые имеют значения по умолчанию:
using System.Diagnostics;
using System.Runtime.CompilerServices;

public void DoProcessing()
{
TraceMessage("Something happened.");
}
public void TraceMessage(string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Trace.WriteLine("message: " + message);
Trace.WriteLine("member name: " + memberName);
Trace.WriteLine("source file path: " + sourceFilePath);
Trace.WriteLine("source line number: " + sourceLineNumber);
}

// Пример вывода:
// message: Something happened.
// member name: DoProcessing
// source file path: c:\Visual Studio Projects\CallerInfoCS\CallerInfoCS\Form1.cs
// source line number: 31

Источник: https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/concepts/attributes/common-attributes
👍1
День пятьдесят седьмой. #TipsAndTricks
8. Вспомогательные Функции
В C# 7.0 вы можете определить вспомогательную функцию внутри метода. Локальная функция может получать доступ ко всем локальным переменным, а также может использовать лямбда-выражение и даже конструкцию async-await. Но эта функция недоступна извне метода.
class Program
{
static void Main(string[] args)
{
int val = 100;
int MyLocalFunction(int value1, int value2)
{
return val + value1 + value2;
}
Console.WriteLine(MyLocalFunction(10, 10));
}
}

Можно использовать более одной локальной функции, а также вложенные друг в друга локальные функции (см. рисунок).

Источник: https://dailydotnettips.com/
День пятьдесят восьмой. #ЗаметкиНаПолях
Создание класса атрибута
Вы можете создавать свои атрибуты, определяя класса атрибута, производный от класса Attribute. Допустим, вы хотите отмечать имя программиста, создавшего тип:
public class AuthorAttribute : System.Attribute
{
private string name;
public double version;

public AuthorAttribute(string name)
{
this.name = name;
version = 1.0;
}
}
- суффикс Attribute в названии класса не обязателен, но соответствует стандарту наименования;
- все неабстрактные атрибуты должны содержать хотя бы один открытый конструктор;
- класс атрибута следует рассматривать как логический контейнер состояния, поэтому должен быть крайне простым, без открытых методов, событий и других членов;
- члены класса должны ограничиваться небольшим набором примитивных типов данных, перечислимыми типами и одномерными массивами (но это не рекомендуется).
Использовать атрибут можно следующим образом:
[Author("P. Ackerman", version = 1.1)]  
class SampleClass { /* … */ }
К классу атрибута можно также применить атрибут типа AttributeUsage, который задаёт следующие параметры:
- AttributeTargets – перечисление целевых объектов для атрибута (по умолчанию AttributeTargets.All);
- AllowMultiple – допустимо ли многократное использование атрибута (по умолчанию false);
- Inherited – будет ли атрибут наследоваться потомками класса (по умолчанию true).
[System.AttributeUsage(
System.AttributeTargets.Class |
System.AttributeTargets.Struct,
AllowMultiple = true,
Inherited = false)
]

Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 18.
-
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/
День пятьдесят девятый. #TipsAndTricks
9. Форматирование выражений в отладчике Visual Studio
Вы можете изменить формат отображения значений в окне Watch, используя форматирование выражений. Чтобы это сделать, введите выражение, за ним поставьте запятую и укажите формат.
Примитивные типы:
- d – Десятичное целое число (было: 0x0065, станет: 101).
- h – Шестнадцатеричное целое число (было: 61541, станет: 0x0000F065).
- nq – строка без кавычек (было: "My String", станет: My String).
Объекты:
- dynamic – Отображает указанный объект в динамическом представлении.
- hidden – Отображает все члены класса, включая непубличные.
- raw – Отображает элемент так, как он отображается в представлении Raw. Действительно только для прокси-объектов, например, Dictionary<T>.
- results – Используется с переменной типа, реализующего IEnumerable или IEnumerable<T>, обычно являющейся результатом запроса. Отображает только члены, содержащие результат запроса.
Поведение:
- ac – Принудительный перерасчет значения выражения.
- nse – Указывает поведение «Без побочных эффектов». Если выражение не может быть интерпретировано, и значение может быть найдено только оценкой (например, с помощью вызова функции), вы получите ошибку.

Источник: https://docs.microsoft.com/en-us/visualstudio/debugger/format-specifiers-in-csharp?view=vs-2017
День шестидесятый. #TipsAndTricks
10. Управление полем значения в отладчике
Мощь современного отладчика заключается в отображении данных объекта при отладке в простой и понятной форме. Поэтому, когда отладчик отображает эту информацию, он должен показывать наиболее интересные значения сразу. К сожалению, отладчику трудно анализировать различные объекты и выделять в них «самое важное». Единственным универсальным решением будет контроль за отображением значений в отладчике, что состоит в добавлении атрибутов к объектам.
Отладка с применением атрибутов даёт разработчику типа возможность указать, как объект будет выглядеть в отладчике. Это достигается применением атрибута DebuggerDisplay. Допустим, вы отлаживаете следующий код:
class Person
{
public string FirstName;
public string LastName;

public Person(string first, string last)
{
this.FirstName = first;
this.LastName = last;
}

public string FullName {get => $"{LastName}, {FirstName}";} }

class Program
{
static void Main(string[] args)
{
List<Person> presidents = new List<Person>
{
new Person("George", "Washington"),
new Person("John", "Adams"),
new Person("Thomas", "Jefferson"),
new Person("James", "Madison"),
new Person("James", "Monroe")
};
}
}
Если вы установите точку прерывания на закрывающей скобке метода Main и посмотрите на значения элементов списка, вы увидите малозначащую строку {Person} (см. рисунок ниже).
Если вы хотите посмотреть свойства объекта James Madison, то вы должны знать, что он четвёртый в списке. Можно переопределить метод ToString типа Person, тогда отладчик вызовет его. Но это приведёт к оценке значения функции, что в сотню раз медленнее обычного вывода значения данных. Кроме того, вывод в отладчике может отличаться от желаемого вывода метода ToString в программе. Поэтому определите атрибут DebuggerDisplay следующим образом:
[DebuggerDisplay("Name: {FullName,nq}")]
class Person
Здесь атрибут приводит к выводу значения свойства FullName без кавычек (формат ‘nq’ – см. форматы отладчика в предыдущем посте).

Источник: https://devblogs.microsoft.com/visualstudio/7-hidden-gems-in-visual-studio-2017/
День шестьдесят первый. #TipsAndTricks
11. Сниппеты
Многие наверняка знакомы со встроенными в Visual Stodio Сниппетами, но стоит отметить, что они расширяемые. Вы можете добавлять свои сниппеты. Директория хранения сниппетов по умолчанию: %имяпользователя%\Documents\Visual Studio 2017\Code Snippets\Visual C#\My Code Snippets.
Давайте для примера создадим сниппет var для определения переменной:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Var</Title>
<Shortcut>var</Shortcut>
<Description>Code snippet for instantiating an object with full type info</Description>
<Author>Anson Horton</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<Default>Example</Default>
<ToolTip>The type to construct</ToolTip>
</Literal>
<Literal>
<ID>variable</ID>
<Default>example</Default>
<ToolTip>The variable name</ToolTip>
</Literal>
<Literal>
<ID>args</ID>
<Default></Default>
<ToolTip>The constructor arguments</ToolTip>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[$type$ $variable$ = new $type$($args$);$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Теперь, когда вы введёте var в файле C# и дважды нажмёте tab, будет вставлен следующий код:
Example example = new Example();
После этого можно клавишей tab перемещаться по литералам и изменять их, при этом все ссылки на одинаковый литерал будут обновляться автоматически. Сниппеты поддерживаются для многих языков в Visual Studio, включая Visual Basic, C#, CSS, HTML, JavaScript, TSQL, TypeScript, Visual C++, XAML и XML.

Источник: https://devblogs.microsoft.com/visualstudio/7-hidden-gems-in-visual-studio-2017/
День шестьдесят второй. #ЗаметкиНаПолях
Исключения. Начало
Конструируя тип, мы заранее пытаемся представить, в каких ситуациях он будет использоваться. Форма определения членов типа (типы данных свойств, параметры методов, возвращаемые значения и т.п.) становится интерфейсом типа. Члены типа определяют допустимые действия с типом и его экземплярами. Если член типа не может решить возложенную на него задачу, должно появляться исключение.
Пример обработки исключений:
try {
// код, требующий корректного восстановления или очистки ресурсов при возникновении исключения
}
catch (InvalidOperationException) {
// обработка исключения типа InvalidOperationException
}
catch (IOException ex) {
// обработка исключения типа IOException
// информация об исключении будет в переменной ex
}
catch {
// обработка остальных типов исключений
}
finally {
// код очистки ресурсов после операций блока try
// этот код исполняется ВСЕГДА
}
// код после блока finally выполняется, если не было сгенерировано исключений, либо если они были перехвачены блоками catch, а новых не генерировалось
Свойства исключений:
1. Исключения представляют собой типы, производные в конечном счете от System.Exception.
2. Блок try используется для выполнения таких инструкций, которые могут создавать исключения. Блок try должен быть связан хотя бы с одним блоком catch или finally.
3. Когда внутри такого блока try возникает исключение, поток управления переходит к первому подходящему обработчику исключений в стеке вызовов. В C# ключевое слово catch обозначает обработчик исключений. Если исключения не возникает, код в блоке catch не выполняется.
4. Если блок catch определяет переменную исключения, ее можно использовать для получения дополнительных сведений о типе созданного исключения.
5. Просмотр блоков catch осуществляется сверху вниз, поэтому исключения должны указываться в порядке от более специализированных к их базовым классам (если они есть) и наконец, к классу System.Exception. Иначе компилятор сообщит об ошибке, т.к. более узкоспециализированные блоки окажутся недостижимыми.
6. Если для созданного исключения не существует обработчиков, выполнение программы прекращается с сообщением об ошибке.
7. Программа может явным образом создавать исключения с помощью ключевого слова throw.
8. Объекты исключения содержат подробные сведения об ошибке, например состояние стека вызовов и текстовое описание ошибки.
9. Код в блоке finally выполняется даже в том случае, если создано исключение. Используйте блок finally, чтобы высвободить ресурсы, например закрыть потоки и файлы, которые были открыты внутри блока try. Блок finally помещается после всех блоков catch. Одному блоку try может соответствовать только один блок finally.

Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 20.
-
https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/exceptions/
День шестьдесят третий.
Visual Studio 2019
Visual Studio 2019 стала доступна для скачивания. С её помощью вы и ваша команда сможете стать ещё более продуктивными в проектировании текущих и будущих проектов в среде, для которой важно каждое нажатие кнопки.
Версия 2019 содержит улучшения 2017й версии в нескольких областях. Она помогает вам быстро получить доступ к коду, упрощая создание клонов в репозитории Git или открытие существующих проектов или папок. Также улучшения коснулись экрана выбора шаблонов при старте нового проекта. При написании кода вы увидите, что улучшилась навигация по коду и добавлено много вариантов рефакторинга, а также показателей состояния документа и очистка кода в один клик с применением сразу нескольких правил рефакторинга. Также улучшена отладка, включая точки останова на данных в приложениях .Net Core, которые помогут вам прерывать выполнение при изменении выбранных вами значений. Кроме того, добавлен помощник в написании кода, основанный на искусственном интеллекте, IntelliCode.
Эти нововведения будут работать как на существующих проектах, так и в новых, от кроссплатформенных приложений на C++ до мобильных приложений .Net для Android и iOS, написанных на Xamarin, до облачных сервисов на Azure. Цель Visual Studio 2019 – поддерживать эти проекты от разработки, через тестирование и отладку до развёртывания, минимизируя для вас необходимость переключаться между разными приложениями, порталами и сайтами.
Скачать Релиз-кандидат Visual Studio 2019 можно здесь: https://visualstudio.microsoft.com/ru/downloads/

Источник: https://devblogs.microsoft.com/visualstudio/visual-studio-2019-code-faster-work-smarter-create-the-future/
День шестьдесят четвёртый. #ЗаметкиНаПолях
Исключения. Продолжение
Советы по обработке исключений
1. Если блок catch определяет переменную исключения, ее можно использовать для получения дополнительных сведений о типе созданного исключения. Эту переменную обычно стоит рассматривать как доступную только для чтения, однако можно добавлять нужную информацию в коллекцию её свойства Data.
2. Программа может явным образом создавать исключения с помощью ключевого слова throw.
3. Объём блока кода внутри try зависит от управления состоянием. Если внутри блока вы собираетесь выполнить набор операций, каждая из которых может стать причиной исключения одного и того же типа, но при этом вы хотите обработать эти исключения по-разному, имеет смысл поместить операции в разные блоки try.
4. При отладке в Visual Studio для просмотра выброшенного исключения нужно добавить в окно Watch специальную переменную $exception.
5. Если обнаружится, что состояние приложения осталось испорченным даже после восстановительных операций в блоках catch или finally, имеет смысл его удалить, чтобы не создавать дополнительных проблем. Это делается методом AppDomain.Unload. После этого приложение перезагружается, чтобы состояние инициализировалось нормально. Если состояние кажется настолько плохим, что имеет смысл завершить работу приложения, используйте статический метод Environment.FailFast. Он завершает процесс без выполнения активных блоков try/finally и без вызовов метода Finalize.

Приёмы работы с исключениями:
1. Активно используйте блоки finally для очистки ресурсов.
- В C# блоки try/finally автоматически создаются компилятором для некоторых конструкций: в lock отключается блокировка, в using вызывается метод Dispose объекта, в foreach вызывается метод Dispose объекта IEnumerator, в деструкторах вызывается метод Finalize базового класса.
2. Не надо перехватывать все исключения.
- К примеру, код библиотеки не может знать, как он будет использоваться в различных приложениях. Исключение должно передаваться вверх по стеку вызовов и обрабатываться кодом приложения. Допустимо перехватывать исключения System.Exception только при условии их повторной генерации в конце блока catch.
3. Корректное восстановление после исключения.
- Иногда заранее известны типы исключений, источником которых может стать метод. Только полностью осознавая обстоятельства, вызывающие конкретные типы исключений, можно перехватывать их и позволять приложению продолжать работу после восстановления.
4. Отмена незавершённых операций при невосстановимых исключениях.
- Когда бизнес-логика требует отменить все ранее выполненные действия при возникновении исключения (банковская транзакция, сериализация группы объектов, транзакция в базе данных и т.п.), имеет смысл перехватывать ВСЕ возможные исключения, отменять сделанные изменения, но обязательно выбрасывать исключение повторно.
5. Скрытие деталей реализации для сохранения контракта
- Иногда бывает полезно после перехвата одного исключения, выбросить исключение другого типа для сохранения деталей реализации. Например, создать исключение RecordNotFoundException для операций поиска в файле или базе данных и выбрасывать его вместо исключений типа FileNotFound, IOException или исключений, связанных с доступом к базе данных.
- При использовании этого приёма стоит перехватывать только те исключения, обстоятельства возникновения которых вы хорошо понимаете. Здесь мы обманываем вызывающий код сообщая неправду о том, что пошло не так, и о месте сбоя. Трассировка стека укажет только место выброса исключения RecordNotFoundException, но не изначального. Это может затруднить отладку.

Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 20.
-
https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/exceptions/
👍1
День шестьдесят пятый. #TipsAndTricks
13. Просмотр производных типов
Иногда бывает полезно посмотреть все типы производные от базового класса. Это особенно актуально для типов из больших фреймворков вроде .NET Framework. Это можно сделать в окне Object Browser. Хитрость в том, что по умолчанию просмотр объектов ограничен вашим решением («My Solution» в списке Browse). Но значение можно изменить. Например, посмотрим типы из библиотеки .NET Framework 4.7.2 (см. рисунок).
Теперь, если вы хотите посмотреть типы производные от System.IO.Stream, просто найдите этот тип, используя строку поиска и разверните папку «Derived Types». Возможно, придётся немного подождать результатов.
Это работает для любой сборки или фреймворка. Но, чтобы использовать это для ссылок, подключённых к вашему проекту, сначала нужно добавить их в отдельный набор «custom component set», нажав на … справа от выпадающего списка Browse.
Источник: https://devblogs.microsoft.com/visualstudio/7-hidden-gems-in-visual-studio-2017/
👍2
День шестьдесят шестой. #ЗаметкиНаПолях
Исключения. Продолжение
Генерация исключений
При реализации своего метода нужно генерировать исключение, если метод не в состоянии решить возложенную на него задачу. При этом важно учесть два фактора:
1. Понять, к какому типу, производному от System.Exception будет относиться ваше исключение. Можно использовать один из типов FCL, либо создать собственный тип. При этом в иерархии типов должно быть как можно меньше базовых классов, т.к. перехват ошибок базового класса также перехватит и ошибки всех производных классов, а это может быть нежелательно.
2. Решить, какое сообщение должно быть передано конструктору исключения. Исключение должно содержать детальную информацию, почему метод не смог решить свою задачу. Обычно конечные пользователи приложения не имеют доступа к исходному коду, а приложения скрывают от них детали ошибок, поэтому в сообщение можно смело помещать всю техническую информацию, необходимую для устранения дефекта.
Выражение throw
Начиная с C# 7.0 throw можно использовать в контекстах, которые ранее не поддерживались:
1. Тернарный оператор
До C# 7.0 нужно было использовать if/else:
private static void DisplayFirstNumber(string[] args)
{
string arg = args.Length >= 1 ? args[0] :
throw new ArgumentException("Массив пустой");
}
2. Оператор объединения с NULL
public string Name
{
get => name;
set => name = value ??
throw new ArgumentNullException("Имя не может быть null", nameof(value));
}

3. Лямбда-выражение или лямбда-метод
DateTime ToDateTime(IFormatProvider provider) => 
throw new InvalidCastException("Преобразование в DateTime не поддерживается.");

Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 20.
-
https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/throw