.NET Разработчик
6.5K 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
День сто шестьдесят четвёртый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по .NET
6. Что такое IL?
Common Intermediate Language (сокращённо CIL или IL) — промежуточный язык, разработанный Microsoft для платформы .NET Framework. Ранее язык назывался Microsoft Intermediate Language (MSIL), однако был переименован для создания стандарта ECMA-335.
IL - это набор независимых от процессора инструкций, которые генерируются компилятором языка при компиляции проекта. В частности, код IL генерируют все компиляторы .NET, входящие в Visual Studio (C#, Managed C++, Visual Basic .NET, Visual J# .NET). Код IL не является исполняемым, но далее обрабатывается средой CLR или другими средами выполнения в исполняемый код. Сборки приложения .NET написаны на IL.

Особенности:
Инструкции IL соответствуют коду, написанному на языке .NET и используемому для загрузки, хранения, инициализации и вызова методов на объектах, а также для арифметических и логических операций, управления потоком исполнения, прямого доступа к памяти, обработки исключений и других операции. JIT-компилятор в CLR преобразует код IL в машинный код, который затем исполняется операционной системой.
По синтаксису и мнемонике IL напоминает язык ассемблера. Его можно рассматривать как ассемблер виртуальной машины .NET. В то же время IL содержит некоторые достаточно высокоуровневые конструкции, повышающие его уровень по сравнению с ассемблером для любой реально существующей машины, и писать код непосредственно на IL легче, чем на ассемблере для реальных машин. Поэтому IL можно рассматривать как своеобразный «высокоуровневый ассемблер».

Выгоды:
1) Взаимодействие языков, так как код на любом языке .NET компилируется в IL.
2) Одинаковая производительность для всех языков .NET.
3) Поддержка различных сред выполнения.

Источники:
-
https://ru.wikipedia.org/wiki/Common_Intermediate_Language
-
https://www.dotnetfunda.com/interviews/show/3948/what-is-msil
День сто шестьдесят пятый. #юмор
День сто шестьдесят шестой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по .NET
7. Что такое JIT-компилятор?
В .NET Framework все языки .NET используют CLR, что решает проблему установки отдельных сред выполнения для каждого из языков программирования. Если на компьютере установлена общеязыковая среда исполнения Microsoft .NET, она может работать на любом языке, совместимом с Microsoft .NET. Языки .NET компилируются в промежуточный язык IL. Перед выполнением IL должен быть преобразован компилятором Just-In-Time (JIT) в машинный код, который представляет собой специфические для процессора команды на той же компьютерной архитектуре, что и JIT компилятор.
Процесс компиляции промежуточного кода в машинный называется JIT-компиляцией Just-In-Time, потому что он не происходит до тех пор, пока сборка не будет размещена на целевой машине. Причина, по которой сборка не компилируется заранее, заключается в том, что можно использовать конкретный JIT-компилятор для вашей ОС и типа процессора. В результате сборка компилируется в максимально быстрый машинный код, оптимизируется и улучшается для вашей конкретной конфигурации.
Вместо того чтобы использовать время и память для преобразования всего IL кода в машинный код, он преобразуется по мере необходимости во время исполнения и сохраняется в результирующем машинном коде, чтобы он был доступен для последующих вызовов.
Среда исполнения предоставляет и другой режим компиляции, называемый генерацией кода во время установки. Режим генерации кода во время установки преобразует IL в машинный код, как это делает обычный JIT-компилятор, но одновременно конвертирует большие блоки кода, сохраняя результирующий машинный код для использования при последующей загрузке и исполнени сборки. Как часть компиляции IL в машинный код, код должен пройти процесс проверки, если администратор не установил политику безопасности, которая позволяет коду обходить проверку. Верификация проверяет IL и метаданные, чтобы выяснить, можно ли определить, что код безопасен по типу, то есть известно, что он имеет доступ только к тем ячейкам памяти, к которым у него есть права доступа.

Источник: https://www.c-sharpcorner.com
День сто шестьдесят седьмой. #МоиИнструменты
Пишите Код Лучше и Быстрее с Помощью Анализаторов Кода Roslyn
Roslyn, платформа компилятора .NET, помогает вам обнаруживать ошибки еще до того, как вы запустите свой код. Одним из примеров является анализатор проверки орфографии, встроенный в Visual Studio. Допустим, вы создаете статический метод и неправильно написали слово static как statc. Вы сможете увидеть эту орфографическую ошибку до того, как запустите свой код.
Анализаторы Roslyn также могут отображать советы по автоматическому исправлению кода с помощью значка лампочки Visual Studio, который позволяет немедленно исправить код.
Но что, если бы вы могли обнаруживать еще больше ошибок?
Коллекции анализаторов Roslyn обеспечивают более подробный анализ кода, но не поставляются со стандартными инструментами Visual Studio. Начиная с Visual Studio 2017 версии 15.8, их можно установить в проект как пакет NuGet. Просто поищите в онлайн пакетах Microsoft.CodeAnalysis.FxCopAnalyzers.
После установки пакета вы можете настроить правила анализатора в окне Solution Explorer. Он появится в блоке References или Dependencies. Если развернуть блок анализаторов, а затем развернуть одну из сборок, вы сможете увидеть все наборы правил. Вы можете просмотреть свойства набора правил, включая его описание, уровень критичности по умолчанию и ссылку на статью с подробным описанием правил, в окне Properties (по правому щелчку мыши или нажав Alt+Enter).
Правила имеют несколько уровней критичности:
- “i” в кружке – Информационное (Info)
- “!” в треугольнике – Предупреждение (Warning)
- “x” в кружке – Ошибка (Error)
- “i” в кружке на светлом фоне – Скрытое (Hidden)
- “↓” в кружке – Отсутствует (None)

Вы можете установить критичность наборов правил в обозревателе решения. Щёлкните правой кнопкой на наборе правил и выберите Set Rule Set Severity. Например, если вы установите серьезность набора правил на Warning, вы получите предупреждение в своем коде там, где эти правила нарушаются. Можно добавлять собственные анализаторы кода, инструкция здесь: https://docs.microsoft.com/ru-ru/dotnet/csharp/roslyn-sdk/tutorials/how-to-write-csharp-analyzer-code-fix

Источник: https://devblogs.microsoft.com/dotnet/write-better-code-faster-with-roslyn-analyzers/
День сто шестьдесят восьмой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по .NET
8. Что такое переносимый исполняемый файл (Portable Executable)?
Переносимый исполняемый (PE) файл – это стандартный файл, который операционная система может загрузить и исполнить. В системе Windows два типа приложений: консольные (Console User Interface, CUI) и графические (Graphical User Interface, GUI). В .NET Framework каждая программа выполняется в операционной системе с помощью CLR.

Управляемый PE-файл состоит из следующих частей:
1. Заголовок PE32(+)
Хранит стандартную информацию, ожидаемую Windows.

2. Заголовок CLR
Cодержит старшую и младшую версии CLR, для которых скомпонован модуль, ряд флагов и маркер MethodDef, указывающий метод точки входа в модуль. Кроме того, заголовок содержит размер и смещение некоторых таблиц метаданных, расположенных в модуле, а также может содержать сигнатуру строгого имени сборки, если используется строгое имя.

3. Метаданные
Блок двоичных данных, состоящий из нескольких таблиц: определений, ссылок и манифеста.
Таблица определений:
- ModuleDef – имя модуля с расширением, идентификатор версии модуля.
- TypeDef – записи для каждого типа, определённого в модуле: имя, базовый тип, флаги доступа и указатели на записи MethodDef, PropertyDef и EventDef этого типа.
- MethodDef – список методов, определённых в модуле: флаги (private, static, virtual и т.п.), сигнатура и смещение в модуле, по которому находится IL-код модуля. А также ссылки на записи в ParamDef для параметров модуля.
- FieldDef – список полей: флаги и тип поля.
- ParamDef – список параметров: флаги (in, out, ref и т.п.), тип и имя.
- PropertyDef – список свойств: имя, флаги, тип и вспомогательное поле.
- EventDef – список событий: имя и флаги.
Таблица ссылок:
- AssemblyRef – записи для каждой сборки, на которую ссылается модуль: имя, версия, региональные стандарты, маркер открытого ключа, флаги и хэш.
- ModuleRef – список PE-модулей, реализующих типы, на которые ссылается текущий модуль: имя файла сборки, расширение.
- TypeRef – список типов, на который ссылается модуль: имя типа и ссылка на его местоположение.
- MemberRef - список членов (поля, метода, свойства или события), на которые ссылается модуль: имя члена, сигнатура и ссылка на TypeRef.
Таблица манифеста:
- AssemblyDef – содержит запись, если модуль идентифицирует сборку: имя сборки, версия, региональные стандарты, флаги, хэш и открытый ключ издателя (может быть null).
- FileDef – список PE-файлов или файлов ресурсов, входящих в состав сборки: имя, расширение, хэш, флаги.
- ManifestResourceDef – список ресурсов, включённых в сборку: имя, флаги, индекс таблицы FileDef, указывающий на файл или поток с ресурсом (ресурс может быть как отдельным файлом, например, изображением, так и храниться в виде потока в PE-файле).
- ExportedTypesDef – список открытых типов, экспортируемых всеми PE-модулями сборки: имя типа, индекс таблицы FileDef и индекс таблицы TypeDef.

4. IL-код
Скомпилированный IL-код модуля.

Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 2.
День сто шестьдесят девятый. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по .NET
9. Что такое сборка?
Сборка - это логическая группировка одного или нескольких управляемых модулей или файлов ресурсов. Это самая маленькая единица с точки зрения многократного использования, безопасности и управления версиями. Управляемые модули сборки могут быть файлами dll или exe в зависимости от типа проекта.
1. Закрытые (private) сборки
Это сборка, которая используется только одним приложением. Предположим, у нас есть проект, в котором мы ссылаемся на DLL, поэтому при создании этого проекта эта DLL будет скопирована в папку bin нашего проекта. Эта DLL становится закрытой сборкой в нашем проекте. Обычно библиотеки DLL, предназначенные для конкретного проекта, являются закрытыми сборками.
2. Совместно используемые (shared) сборки
Сборки, которые можно использовать более чем в одном проекте, известны как совместно используемые. Такие сборки обычно устанавливаются в GAC. Сборки, установленные в GAC, становятся доступными для всех приложений .NET на этом компьютере.

GAC
GAC (Global Assembly Cache, Глобальный Кэш Сборок) - это место на диске, где располагаются совместно используемые сборки. До .NET 3.5 GAC располагался в C:\Windows\assembly, в более поздних версиях - в C:\Windows\Microsoft.NET\assembly\GAC_MSIL.

Установка сборки в GAC
GAC обладает особой структурой и содержит множество вложенных каталогов, имена которых генерируются по определённому алгоритму. Ни в коем случае нельзя копировать файлы сборок в GAC вручную. Для установки сборки в GAC сначала необходимо создать строгое имя для сборки, поскольку в GAC устанавливаются только сборки со строгим именем. Все остальные сборки называются сборками со слабым (нестрогим) именем, и их нельзя сохранить в GAC.
Для создания строгого имени нужно получить пару ключей с помощью утилиты Strong Name SN.exe, поставляемой в составе .NET Framework SDK и Visual Studio. После этого сборка компилируется вместе с файлом ключей. При указании такого файла при компиляции компилятор подписывает сборку закрытым ключом, а открытый ключ встраивает в манифест сборки.
После этого подписанную сборку со строгим именем можно установить в GAC с помощью утилиты GACUtil.exe. Подписание файла закрытым ключом гарантирует, что именно держатель соответствующего открытого ключа является производителем сборки. Кроме того, рассчитывается хэш содержимого файлов и сохраняется в таблице FileDef манифеста сборки. Это предохраняет сборку от изменения. При установке сборки в GAC хэши файлов рассчитываются заново и сравниваются со значениями из таблицы FileDef. Если хотя бы одно не совпадает, значит файлы были изменены, и установка сборки в GAC закончится неудачей.

Источники:
-
https://www.c-sharpcorner.com
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 3.
День сто семидесятый. #BestPractices
Рекомендации по использованию методов расширения. Начало
1.
У вас должна быть веская причина использовать метод расширения вместо экземплярного метода. Одна из таких причин - когда вы имеете дело с не принадлежащими вам типами, например, из сторонней библиотеки.
2. Используйте метод расширения, когда функциональность наиболее соответствует расширяемому типу. Например, разумно иметь метод расширения date.AddDays(numDays), который расширяет тип DateTime. Но не имеет смысла делать наоборот: days.AddToDate(date), который расширяет int.
3. Добавляйте методы расширения к интерфейсам, чтобы добавить общие функциональные возможности к классам, не имеющим общего базового класса. Яркий пример – методы LINQ, расширяющие интерфейс IEnumerable.
4. Используя серию методов расширения с тем же типом возврата, вы можете добиться синтаксиса функционального программирования. Например:
public static IEnumerable<Customer> AboveAge(this IEnumerable<Customer> customers, int age)
{
return customers.Where(c => c.Age > age);
}
public static IEnumerable<Customer> OnlyMale(this IEnumerable<Customer> customers)
{
return customers.Where(c => c.Gender == "Male");
}
public static IEnumerable<Customer> OnlyFemale(this IEnumerable<Customer> customers)
{
return customers.Where(c => c.Gender == "Female");
}

// использование:
var potentialBuyers = customers.AboveAge(42).OnlyFemale();

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

Замечание: как и в большинстве руководств по стилю кодирования, вышеизложенное является сугубо личным мнением.

Источник:
https://michaelscodingspot.com/
День сто семьдесят первый. #BestPractices
Рекомендации по использованию методов расширения. Окончание

5.
Вы можете использовать методы расширения для разделения ответственности, когда вы не хотите внедрять некоторую зависимость в расширяемый тип. Например, вы можете расширить Customer с помощью такого метода:
public static AdjustLastSeen(this Customer customer, TimeZoneManager timeZoneManager) { … }
В примере выше, если вы не хотите внедрять зависимость Customer от TimeZoneManager, вы можете добиться этого с помощью метода расширения. Обратите внимание, что в подобных случаях методы расширения могут быть не лучшим вариантом.
6. Если вы не уверены, какой тип расширять, не используйте методы расширения. Например, чтобы построить дом из кирпича (brick) и раствора (mortar), я могу расширить кирпич с помощью brick.BuildHouse(mortar). Или можно расширить раствор с помощью mortar.BuildHouse(brick). Поскольку ни один из методов не является более подходящим, чем другой, вероятно, методом расширения использовать не стоит.
7. Избегайте наличия состояния в ваших методах расширения. Лучше всего вообще избегать наличия состояния в статических классах, потому что это значительно затрудняет тестирование.
Одно из возможных исключений - если вы хотите использовать мемоизацию (кеширование входных и выходных данных для повторного использования результатов). Но это совсем другая история.
8. Избегайте расширения примитивных типов. Есть несколько причин для этого. С одной стороны, будет очень трудно найти метод, который наиболее соответствует примитивному типа. Кроме того, Visual Studio будет всегда показывать этот метод расширения в IntelliSense при каждом использовании этого примитивного типа.
9. Группируйте методы расширения для одного типа в одном классе. Так будет легче найти эти методы в коде. Кроме того, у всех них должно быть много общего, поскольку они относятся к одному и тому же типу.

Замечание: как и в большинстве руководств по стилю кодирования, вышеизложенное является сугубо личным мнением.

Источник:
https://michaelscodingspot.com/
172. applied-tdd.gif
140.4 KB
День сто семьдесят второй. #юмор
День сто семьдесят третий. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по .NET
10. Что такое сборщик мусора?
Мусор состоит из объектов, созданных во время выполнения программы в управляемой куче, которые больше не доступны программе.
Сборщик мусора (Garbage Collector - GC) является частью .NET Framework, которая выделяет и освобождает память для ваших приложений .NET. CLR управляет выделением и освобождением управляемого объекта в памяти. Программисты C# никогда не делают этого напрямую, этим управляет сборщик мусора.
Объекты .NET размещаются в области памяти, называемой управляемой кучей. Они будут автоматически уничтожены сборщиком мусора. Распределение кучи происходит только при создании экземпляров классов. Это избавляет программиста от необходимости вручную удалять объекты, которые больше не требуются для выполнения программы. Такое повторное использование памяти помогает уменьшить объем памяти, необходимый программе для работы. Объекты размещаются в куче непрерывно, один за другим. Это очень быстрый процесс, так как это просто добавление значения к указателю.
Процесс освобождения памяти называется сборкой мусора. Он освобождает только те объекты, которые больше не используются в приложении. Корень - это место в хранилище, содержащее ссылку на объект в управляемой куче. CLR проверяет объекты в управляемой куче, чтобы определить, доступны ли они из приложения (имеют ли корень), и создает граф доступных объектов в куче.
Предположим, что управляемая куча содержит набор объектов с именами A, B, C, D, E, F и G (см. рисунок ниже). Во время сборки мусора эти объекты проверяются на наличие активных корней. После построения графа недоступные объекты (в данном случае C и F) помечаются как мусор.
После этого объекты помеченные, как мусор удаляются из памяти. В этот момент оставшееся пространство в куче сжимается, что, в свою очередь, заставляет CLR изменить набор активных корней приложения, чтобы обращение происходило к правильному месту в памяти. Наконец, указатель следующего объекта изменяется, чтобы указывать на следующее свободное место.

Поколения объектов
Для повышения производительности освобождения памяти управляемая куча разделена на сегменты, называемые «поколениями». Существует 3 поколения: 0, 1 и 2. Идея поколений проста: чем дольше объект существует, тем дольше он доступен и тем реже сборщик мусора будет проверять его корень.
Когда объекты только что созданы, они помещаются в Поколение 0 (Gen 0).
Когда Gen 0 заполняется, GC выполняет сборку мусора. При этом удаляются все недоступные объекты из кучи. Все доступные объекты переходят в Поколение 1 (Gen 1). Сбор мусора в Gen 0 - довольно быстрая операция.
Когда Gen 1 заполняется, выполняется сборка мусора Gen 1. Все объекты, которые сохранились после сборки мусора, повышаются до Gen 2. При этом также выполняется сборка в Gen 0.
Когда заполнено Gen 2, GC выполняет полную сборку мусора. Сначала выполняется сборка в Gen 2, затем в Gen 1 и Gen 0. Если памяти для новых объектов всё ещё недостаточно, GC выбрасывает исключение OutOfMemory.
Во время полной сборки мусора GC должен пройти через все объекты в куче, поэтому этот процесс может оказать большое влияние на системные ресурсы.

Источник: https://www.c-sharpcorner.com
День сто семьдесят четвёртый. #BestPractices
Когда использовать LINQ с синтаксисом запроса вместо методов. Начало
Выражения LINQ можно написать в двух вариантах - синтаксис запроса и синтаксис методов. Например, следующие запросы идентичны:
var numbers = Enumerable.Range(1, 100); //1,2,...,100
//Запрос:
var query = from n in numbers
where n % 3 == 0
select n * 2;
//Методы:
var method = numbers
.Where(n => n % 3 == 0)
.Select(n => n * 2);

По некоторым причинам большинство разработчиков (включая меня) чувствуют себя более комфортно с синтаксисом методов. Возможно, причина в том, что программисты привыкли к регулярным вызовам методов. В отличие от синтаксиса запроса, который является своего рода новым языком (ну, вроде как SQL, но он все же менее привычен, чем C#).
Нет никакого явного преимущества одного синтаксиса над другим. Фактически любой синтаксис запроса может быть преобразован в синтаксис методов.
Однако есть несколько случаев, когда синтаксис запроса лучше, то есть он делает код более читабельным:

1. Ключевое слово "let"
Ключевое слово let позволяет сохранить результат для последующего использования в запросе. Вот пример:
var querySyntax =
from person in people
let yearsWorking = GetYearsWorking(person)
where yearsWorking > 4
orderby yearsWorking
select person.Name;

var methodSyntax = people
.Select(person => new {
YearsWorking = GetYearsWorking(person), Name = person.Name })
.Where(x => x.YearsWorking > 4)
.OrderBy(x => x.YearsWorking)
.Select(x => x.Name);
Как видите, с синтаксисом запросов все красиво и чисто. Синтаксис метода не является ужасным, но он требует создания анонимные классов и использования их в остальной части запроса. Поэтому, когда вы хотите «сохранить» значение в дополнение к запрашиваемой коллекции, рассмотрите возможность использования предложения let.

2. OrderBy по нескольким полям
Как в синтаксисе запроса, так и в синтаксисе методов вы можете легко выполнить упорядочивание по нескольким полям. Например, мы можем упорядочить людей по возрасту, а затем по доходу, где возраст - первый, а доход - второй. Это означает, что люди с одинаковым возрастом будут упорядочены по доходам:
var people = new Person[]
{
new Person() {Age = 20, Income = 5000, Name = "Peter"},
new Person() {Age = 30, Income = 8000, Name = "Alfredo"},
new Person() {Age = 30, Income = 7000, Name = "Bo"},
new Person() {Age = 20, Income = 4000, Name = "Jo"},
new Person() {Age = 20, Income = 6000, Name = "Amanda"},
new Person() {Age = 30, Income = 5500, Name = "Maxim"},
};

var querySyntax = from person in people
orderby person.Age, person.Income
select $"{person.Age} {person.Income} {person.Name}";
var methodSyntax = people
.OrderBy(person => person.Age)
.ThenBy(person => person.Income)
.Select(person => $"{person.Age} {person.Income} {person.Name}");

//result
//20 4000 Jo
//20 5000 Peter
//20 6000 Amanda
//30 5500 Maxim
//30 7000 Bo
//30 8000 Alfredo
Я признаю, что оба варианта хороши, и разница не так велика, как в других случаях. Но синтаксис запроса все же выглядит лучше.

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

Замечание: как и в большинстве руководств по стилю кодирования, вышеизложенное является сугубо личным мнением.

Источник:
https://michaelscodingspot.com/
👍2
День сто семьдесят пятый. #BestPractices
Когда использовать LINQ с синтаксисом запроса вместо методов. Продолжение

3. Несколько источников данных
Если у вас есть несколько источников данных для запроса, синтаксис запроса будет предпочтительнее. Причина в том, что вы можете использовать ключевое слово from несколько раз. Например:
var rows = Enumerable.Range(1, 3); //1,2,3
var columns = new string[] { "A", "B"};
var querySyntax = from row in rows
from col in columns
select $"cell [{row}, {col}]";
var methodSyntax =
rows.SelectMany(row => columns, (r, c) => $"cell [{r}, {c}]");
foreach (var cell in methodSyntax)
{
Console.WriteLine(cell);
}
//Вывод:
//cell[1, A]
//cell[1, B]
//cell[2, A]
//cell[2, B]
//cell[3, A]
//cell[3, B]
Цель здесь - получить коллекцию со всеми возможными комбинациями из 2 источников. С синтаксисом запроса код прост и не требует пояснений. А синтаксис методов вовсе не так очевиден для понимания.

4. GroupBy или group
Метод расширения GroupBy очень похож на group в запросе. Например:
var names = new string[] { "Alex", "George", "Alfredo", "Bo", "Greg", "Maxim" };
var querySyntax = from name in names
group name by name[0];
var methodSyntax = names
.GroupBy(name => name[0], name => name);
foreach (var pair in querySyntax)
{
var names1 = string.Join(", ", pair.ToList());
Console.WriteLine($"Key = {pair.Key} Names = {names1}");
}
//Вывод:
//Key = A Names = Alex, Alfredo
//Key = G Names = George, Greg
//Key = B Names = Bo
//Key = M Names = Maxim
Опять же, синтаксис методов не совсем ясен. Что означает второй параметр? Конечно, если немного подумать, смысл становится понятен. Но я не хочу думать, когда я смотрю на код, я хочу читать его как книгу. Детскую книгу, если это возможно.

5. Объединения
Как правило, всякий раз, когда вам нужно объединить коллекции, синтаксис запроса будет более читаемым. Вот внутреннее объединение, например:
var categories = new Category[]
{
new Category() {Name="Игрушки", ID=1},
new Category() {Name="Приборы", ID=2}
};
var products = new Product[]
{
new Product(){Name="Кукла", CategoryID=1},
new Product(){Name="Блендер", CategoryID=2},
new Product(){Name="Утюг", CategoryID=2},
new Product(){Name="Медведь", CategoryID=1}
};
var querySyntax =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name };
var methodSyntax = categories.Join(products,
category => category.ID,
prod => prod.CategoryID,
(category, prod) => new {ProductName = prod.Name, Category = category.Name});
В синтаксисе методов сравниваются 2-й и 3-й параметры объединения. Но в отличие от синтаксиса запроса, это не совсем понятно из кода. В синтаксисе запросов это намного понятнее.

Замечание: как и в большинстве руководств по стилю кодирования, вышеизложенное является сугубо личным мнением.

Источник:
https://michaelscodingspot.com/
👍1
День сто семьдесят шестой. #юмор
День сто семьдесят седьмой. #ЧтоНовенького
Повысьте Уровень Знаний о VS 2019 с Pluralsight
С запуском Visual Studio 2019 в апреле Microsoft объявили о партнерстве с Pluralsight для предоставления нового учебного контента, который поможет вам развить свои навыки в Visual Studio 2019. Теперь доступны все 10 курсов (более 14 часов контента) о Visual Studio 2019 на Pluralsight. Вы также сможете оценить свой текущий уровень квалификации с оценкой IQ Pluralsight Skill, которая предложит рекомендации по курсу, а после, по мере прохождения курса, вы можете оценить свой прогресс.
10 видеокурсов разделены на категории по уровням подготовки:
1. Новичок
Эти курсы разработаны, чтобы помочь вам освоить наиболее распространенные действия в Visual Studio. Если вы использовали предыдущие версии Visual Studio, ознакомьтесь с курсом «What’s New in Visual Studio 2019», чтобы быстро освоить все новые функции. Если вы новичок в Visual Studio, вам нужно пройти курс «Visual Studio 2019 Getting Started». Затем улучшите свои навыки отладки на курсе «Visual Studio 2019: Debugging».
2. Средний
Отточите свои навыки с помощью курсов из этого раздела, и научитесь управлять своими репозиториями Git с помощью Visual Studio. Вы можете узнать о возможностях тестирования, доступных в Visual Studio, функциях анализа кода и о том, как Visual Studio помогает переносить решения в Azure:
- Using Git for Source Control in Visual Studio 2019
- Testing .NET Code in Visual Studio 2019
- Code Analysis in Visual Studio 2019
- Migrating Applications and Services to Azure with Visual Studio 2019
3. Продвинутый
Выделитесь среди других знаниями, которые вы получите в этом разделе. Всего за полчаса вы можете научиться пользоваться Visual Studio Live Share. Узнайте о расширенных функциях отладки и о том, как создавать собственные облачные решения в Visual Studio.
- Play by Play: Visual Studio Live Share
- Advanced Debugging with Visual Studio 2019
- Building Cloud-native Solutions for Azure with Visual Studio

Курс доступен здесь: https://app.pluralsight.com/paths/skills/visual-studio-2019

Замечания:
- Курсы (естественно) на английском.
- Подписчики Visual Studio получают бесплатный доступ ко всем курсам Pluralsight на 6 месяцев. А курс по Visual Studio, судя по всему, бесплатный.

Источник: https://devblogs.microsoft.com/visualstudio/skill-up-on-visual-studio-2019-with-pluralsight/
This media is not supported in your browser
VIEW IN TELEGRAM
День сто семьдесят восьмой. #ЧтоНовенького
Что Нового в Visual Studio 16.2
Visual Studio 16.2 стала доступна для обычной загрузки. Вот некоторые обновления в этой версии.
Test Explorer теперь обеспечивает лучшую обработку больших наборов тестов, более простую фильтрацию, закладки плейлистов тестов и настраиваемые столбцы для точной настройки отображаемой тестовой информации.
Версия 16.2 поддерживает отладку JavaScript в новом браузере Microsoft Edge Insider для проектов ASP.NET и ASP.NET Core. Для этого установите браузер, установите точку останова в JavaScript приложения и запустите сеанс отладки.
Кроме того вернули пункт меню Sort Usings, появилась возможность преобразовывать операторы switch в выражения switch, а также сгенерировать параметр для переменной из меню Quick Actions.

Источник: https://devblogs.microsoft.com/visualstudio/
День сто семьдесят девятый. #юмор
Бывало такое? )))
День сто восьмидесятый. #ЗаметкиНаПолях
Многопоточность. Начало
Многопоточность позволяет увеличивать скорость реагирования приложения и, если приложение работает в многопроцессорной или многоядерной системе, скорость его исполнения.
Процесс — это набор ресурсов, используемый отдельным экземпляром приложения. Операционная система использует процессы для разделения исполняемых приложений. Поток — это основная единица, которой операционная система выделяет время процессора.

Когда используется многопоточность
Несколько потоков используются, чтобы повысить скорость отклика вашего приложения и использовать преимущества многопроцессорной или многоядерной системы для увеличения скорости приложения.
1. В приложении основной поток отвечает за пользовательский интерфейс и отвечает на действия пользователя. Рабочие потоки используются для выполнения ресурсоёмких операций, которые в противном случае заняли бы основной поток и сделали бы пользовательский интерфейс невосприимчивым. 2. Выделенный поток может использоваться для получения данных по сети или от внешнего устройства.
3. Если ваша программа выполняет операции, которые могут исполняться параллельно, общее время выполнения можно уменьшить, выполнив эти операции в отдельных потоках и запустив программу в многопроцессорной или многоядерной системе. В такой системе использование многопоточности может ускорить вычисления наряду с повышением отзывчивости приложения.
4. Потоки позволяют изолировать один код от другого, повышая надёжность приложения. В отдельном потоке можно запускать сторонний код, если нет уверенности в его надёжности и качестве.
5. Иногда код проще писать, если предположить, что он будет исполняться в собственном потоке. Однако при этом потребуются дополнительные ресурсы и, возможно, код синхронизации, что снизит эффективность кода.

Приоритеты потоков
Операционные системы с многозадачностью должны использовать некий алгоритм, определяющий порядок и продолжительность исполнения потоков. Windows называют многопоточной ОС с вытесняющей многозадачностью, т.к. каждый поток может быть остановлен в произвольный момент и вместо него выбран для исполнения другой. Чтобы управлять этим процессом, каждому потоку назначается уровень приоритета от 0 (самого низкого) до 31 (самого высокого). При выборе потока, который будет передан процессору, сначала рассматриваются потоки с самым высоким приоритетом. В Windows определены приоритеты процессов (приложений): Idle, Below Normal, Normal (по умолчанию), Above Normal, High и Realtime. Кроме того, поддерживаются следующие относительные приоритеты потоков: Idle, Lowest, Below Normal, Normal, Above Normal, Highest, Time-Critical. Соотношение между приоритетом процесса и относительным приоритетом потока и определяет итоговый уровень приоритета процесса. Например, по умолчанию оба приоритета установлены в Normal, и итоговый приоритет процесса – 8. Потоки с относительным приоритетом Time-Critical при любом приоритете процесса, кроме Realtime, имеют приоритет 15. В Realtime процессе потоки имеют приоритеты от 16 до 31.

Фоновые и активные потоки
Фоновые потоки приложения завершаются немедленно и без появления исключений при завершении активных потоков. Таким образом активные потоки используются для исполнения заданий, которые обязательно нужно завершить. Фоновые потоки можно оставить для некритичных операций. Потоки можно превращать из активного в фоновый и обратно. Основной поток приложения и все потоки, явно созданные через создание объекта Thread, являются активными. Потоки из пула потоков (ThreadPool) по умолчанию фоновые.
Особенности потоков
- В настоящее время потоки в CLR аналогичны Windows-потокам, но не исключено, что со временем эти понятия начнут различаться. Может появиться собственная концепция логического потока, не совпадающая с физическим потоком Windows.
- Для каждого потока выделяются память для хранения информации о потоке, кэша потока, пользовательского стека и т.п.
- В произвольный момент времени Windows передаёт процессору на исполнение один поток. Этот поток исполняется в течение некоторого временного интервала, называемого тактом. После завершение такта происходит переключение на другой поток. Это называется переключением контекста.
- Из-за затрат памяти и времени на переключение контекста, затрат на создание, управление и завершение потока, затрат на сборку мусора и т.п. использования потоков нужно по возможности избегать. Лучше прибегать к доступному в CLR пулу потоков (об этом далее).

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

Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 25.
-
https://docs.microsoft.com/dotnet/standard/threading/threads-and-threading
День сто восемьдесят первый. #ЗаметкиНаПолях
Многопоточность.
2. Пул потоков в CLR
CLR способна управлять собственным пулом потоков. Для каждого процесса существует свой пул, используемый всеми доменами приложений в CLR. Пул потоков позволяет найти золотую середину в ситуации, когда малое количество потоков экономит ресурсы, а большое позволяет воспользоваться преимуществами многопроцессорных систем, а также многоядерных и гиперпотоковых процессоров. Он действует по эвристическому алгоритму, создавая или уничтожая потоки по мере необходимости.
В пуле различают два типа потоков: рабочие потоки (worker thread) и потоки ввода-вывода (I/O thread). Первые используются для асинхронных вычислительных операций, вторые служат для уведомления кода о завершении асинхронной операции ввода-вывода.
Для добавления в очередь пула потоков асинхронных вычислительных операций обычно вызывают один из методов QueueUserWorkItem класса ThreadPool. В метод передаётся делегат WaitCallback, а также может передаваться объект состояния state:
static void Main(string[] args)
{
Console.WriteLine("Основной поток: вызываем асинхронную операцию");
ThreadPool.QueueUserWorkItem(Compute, 5);
Console.WriteLine("Основной поток: выполняем другую работу...");
Thread.Sleep(10000);
Console.ReadLine();
}

private static void Compute(object state)
{
//Метод выполняется потоком из пула
Console.WriteLine($"В Compute: state={state}");
Thread.Sleep(1000);
}
После возвращения управления асинхронным методом, поток возвращается в пул и ожидает следующего задания.

Возможны ситуации, когда требуется явно создать поток, исполняющий конкретную вычислительную операцию:
- Поток требуется запустить с нестандартным приоритетом (хотя, этого делать не рекомендуется).
- Чтобы приложение не закрылось до завершения потоком задания, требуется, чтобы поток исполнялся в активном режиме. В примере выше по умолчанию метод Compute выполняется в фоновом потоке, поэтому приложение может прекратить работу перед тем, как завершится выполнение этого метода.
- Задания, связанные с критически важными вычислениями, которые могут выполняться долго, лучше не отдавать на откуп пула потоков, а выделить им отдельный поток.
- Если есть необходимость преждевременно завершить исполняющийся поток через Thread.Abort().

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

Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 26.
👍2
День сто восемьдесят второй. #ЗаметкиНаПолях
Многопоточность
3. Скоординированная отмена
.NET предлагает стандартный шаблон операций отмены. Он называется скоординированным (cooperative), то есть необходима явная поддержка отмены операций. Это значит, что как код, выполняющий отменяемую операцию, так и код, пытающийся отменить операцию, должны использовать одинаковые типы.
В вызывающем коде создаётся объект CancellationTokenSource. C его помощью можно создать структуру CancellationToken, которая передаётся вызываемому коду. Для отмены операции вызывается метод Cancel объекта CancellationTokenSource.
Вот наиболее полезные члены структуры CancellationToken:
- bool IsCancellationRequested – вызываемый код может периодически обращаться к этому свойству, чтобы узнать, не запрошена ли отмена операции;
- void ThrowIfCancellationRequested() – метод используется в заданиях (Task) аналогично предыдущему свойству;
- CancellationToken None – статическое свойство, обозначающее отсутствие токена отмены, чтобы исключить возможность отмены операции;
- CancellationTokenRegistration Register(…) – метод используется для регистрации одного или нескольких делегатов обратного вызова, которые будут вызваны при отмене операции. Возвращаемая методом структура CancellationTokenRegistration содержит метод Dispose, который позволяет отменить регистрацию.

В примере ниже токен отмены передаётся методу Compute, внутри которого периодически проверяется свойство IsCancellationRequested. Когда пользователь нажимает Enter, вызывается отмена операции, и на следующей итерации цикла он прерывается:
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(o => Compute(cts.Token, 1000));
Console.WriteLine("Нажмите <Enter> для отмены...");
Console.ReadLine();
cts.Cancel();
Console.ReadLine();
}

private static void Compute(CancellationToken token, int countTo)
{
for (int i = 0; i < countTo; i++)
{
if(token.IsCancellationRequested)
{
Console.WriteLine("Счёт отменён");
break;
}
Console.WriteLine(i);
Thread.Sleep(200);
}
Console.WriteLine("Счёт закончен");
}

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

Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 26.