.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 Preview 1
Кажется, не так давно мы обсуждали вкусности .NET 5, а теперь мы уже переходим к .NET 6. Помню времена, когда даже младшие версии фреймворка иногда содержали огромные изменения. Например, async/await был добавлен в версию .NET Framework 4.5, которая в наши дни означала бы «незначительное» обновление. И вообще, между версиями 1.0 и 4.8 прошло 17 лет.

Первая версия .NET Core была выпущена в 2016 году, и вот мы в 2021 году, всего 5 лет спустя, уже готовы увидеть превью .NET Core 6. Скорость разработки современного программного обеспечения просто поражает. Прошли те времена, когда разработчики запирались в отделах и работали по три года до крупного релиза.

Вы можете скачать .NET 6 Preview 1 здесь: https://dotnet.microsoft.com/download/dotnet/6.0

Что нового?
Как правило, первый предварительный выпуск закладывает основу для будущих новинок и не обязательно содержит большого количества «игрушек», с которыми можно поиграть. Однако некоторые функции действительно были добавлены:
1. Первая итерация переноса Xamarin в .NET для унификации платформ, то есть возможности создавать приложения для Android/IOS в .NET.

2. Первая попытка использования Blazor для настольных приложений (на первый взгляд кажется, что это очень похоже на использование Electron, например, это использование элемента веб-представления в настольных приложениях).

3. Кажется, говорят об улучшении функции горячей перезагрузки. Сложно найти много информации по этому поводу. В .NET CLI уже есть «dotnet watch», но это скорее полная сборка, чем приятная итеративная горячая перезагрузка.

4. Улучшение однофайловых приложений, так чтобы они фактически выполнялись из этого единственного файла, а не распаковывались во временные каталоги. Это уже имело место для однофайловых приложений под Linux в .NET 5, но в .NET 6 эта функциональность была расширена для Windows и Mac.

5. appsettings.json в Visual Studio и VSCode (с расширением C#) теперь имеет автозаполнение для часто используемых конфигураций в ASP.NET Core, включая настройку ведения журнала, фильтрации хостов и Kestrel.

6. WPF теперь поддерживается в ARM64.

Основной путь изменений в .NET 6 (и даже .NET 5) - это объединение различных платформ и фреймворков, которые находятся под знаменем .NET. В .NET 5 это была в основном разработка для настольных компьютеров, а в .NET 6 - это разработка мобильных приложений с Xamarin.

Источник: https://dotnetcoretutorials.com/2021/02/21/net-6-preview-1-has-been-released/
День семьсот пятьдесят седьмой. #Оффтоп #ЗадачиНаСобеседовании
Что я Узнал о C# из Собеседований. Начало
Недавно я прошел серию собеседований в нескольких крупнейших технологических компаниях. Процессы собеседований в них сильно отличались, но у них также было много общего, например, упор на задачи на написание кода. Сортировка, нахождение всех возможных комбинаций или нахождение выхода из лабиринта. Я не знаю, как это связано с реальной разработкой ПО. Я не помню, чтобы мне когда-либо приходилось самому писать алгоритм сортировки в повседневной работе. Тем не менее, очевидно, что разработчик, способный решить эти проблемы, будет лучше справляться и с проблемами реальной жизни. Поэтому я хочу описать, что я узнал о C# во время собеседований. У меня больше 10 лет опыта в C#, но повседневная разработка и прохождение интервью – это разные вещи.

1. Многомерные массивы могут быть полезны
Не думаю, что я когда-либо использовал многомерный массив в своей работе. Конечно, я иногда использовал список списков List<List<T>> и, возможно, список массивов List<int[]>, а иногда даже список словарей массивов List<Dictionary<int,string[]>>. Но я обнаружил, что многомерные массивы очень полезны в упражнениях по кодированию.

Многомерные массивы - это не то же самое, что массивы массивов, например int[][] (зубчатые массивы). Последние представляют собой набор массивов, каждый из которых может иметь разную длину. Многомерный массив больше подходит для решения общих задач, таких как представление двухмерного лабиринта или трехмерного куба. Если вы собираетесь на собеседование в ближайшее время, освежите в голове синтаксис:
int[,] arr = new int[3, 2]
{{1, 2},{3, 4},{5, 6}};

int dimLen1 = arr.GetLength(0); //3
int dimLen2 = arr.GetLength(1); //2
var p00 = arr[0, 0]; //1
var p01 = arr[0, 1]; //2
var p10 = arr[1, 0]; //3

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

2. Используйте кортежи, вместо классов
Я довольно редко использую кортежи. Вероятно потому, что я пока не привык к их более красивому синтаксису. Обычно я выбираю класс или структуру. Классы делают код более структурированным и, возможно, более читаемым. Но на самом деле у кортежей очень хороший и, что важно, более компактный синтаксис. Писать нужно меньше, менять нужно меньше. Эти вещи действительно важны на собеседовании. Нужно тратить минимум времени на ввод кода, чтобы у вас было больше времени на размышления.

Допустим, у меня есть метод, который возвращает точку в трёхмерном массиве. При использовании класса я бы написал:
class Point3D {
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
private Point3D Calc() {…}

Тогда как с кортежами всё проще:
private (int X, int Y, int Z) Calc(){ ... }

Имейте в виду, что на собеседовании вы будете писать в своего рода онлайн-блокноте, где у вас нет сниппетов, автозаполнения и прочих прелестей, к которым вы привыкли в Visual Studio.

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

Источник:
https://michaelscodingspot.com/what-i-learned-about-c-from-job-interviews/
Автор: Michael Shpilt.
День семьсот пятьдесят восьмой. #Оффтоп #ЗадачиНаСобеседовании
Что я Узнал о C# из Собеседований. Продолжение
Начало

3. Бинарные операции – это вещь!
Как часто вы используете операторы <<, >>, & и | в ваших приложениях? Думаю, не часто. Я тоже, но они могут быть довольно полезны. Небольшое напоминание:
int a = 15;
Convert.ToString(a, to_base: 2); //1111
//сдвиг вправо дважды (деление на 4)
a = a >> 2; //11
//сдвиг влево трижды (умножение на 8)
a = a << 3; //11000
a = a & 0b_11111; // не изменяется
// остаётся 1000, т.к. левый бит обнуляется
a = a & 0b_1111; //1000
a = a | 0b_1; // становится 1001
a = a | 0b_110; // становится 1111

Одна из особенностей двоичного исчисления заключается в том, что итерация по основанию 2 может быть полезна в задачах на перестановку. Например: для заданного массива элементов, распечатать все возможные комбинации этих элементов, в которых каждый элемент может либо присутствовать, либо отсутствовать. Порядок не имеет значения. То есть для массива ["a", "b", "c"] вывод будет следующим:
"", a, b, c, ab, ac, bc, abc

Теперь рассмотрим итерацию в двоичном формате от 0 до 2^3. Если каждая цифра описывает элемент массива, который присутствует или нет, то это один из способов распечатать все возможные итерации. Требуемый выше результат можно описать как:
000, 001, 010, 100, 110, 101, 011, 111

4. Полезные штуки со строками и массивами
Большинство методов, используемых в задачах, аналогичны методам, используемым в реальной жизни. Для строк это .Substring, .Contains, .Replace, string.Equals, .ToLower, .ToUpper и т.д. Один из методов, полезных в этих задачах, но редко используемый в моей работе, - это string.Join:
var joined = string.Join(",", 
new[]{"a","b","c"}); // "a,b,c"

Для массивов есть полезный метод Array.Sort, который может принимать делегат Comparison<T> для нужной вам сортировки. Предположим, вы хотите отсортировать группу строк по последней букве:
var words = new[]{"cat", "job", "zebra", "row"};
Array.Sort(words, (w1, w2) => {
var last1 = w1[w1.Length-1];
var last2 = w2[w2.Length-1];
return last1 < last2 ? -1 : 1;
//как вариант last1.CompareTo(last2);
});
// zebra, job, cat, row

Еще один полезный метод - Array.Copy. Помимо прочего, он может копировать фрагмент массива в новый массив:
var words = new[]{"cat", "job", "zebra", "row"};
string[] dest = new string[2];
Array.Copy(words, sourceIndex: 1,
dest, destinationIndex: 0, length: 2);
// job, zebra

Конечно, есть и другие способы это сделать, например, LINQ или с помощью диапазонов.

Источник: https://michaelscodingspot.com/what-i-learned-about-c-from-job-interviews/
Автор: Michael Shpilt.
День семьсот пятьдесят девятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
78. Шаг назад и автоматизация, автоматизация, автоматизация
Я работал с программистами, которые, когда их просили произвести подсчёт строк кода в модуле, вставляли все файлы в один текстовый редактор и использовали его функцию подсчёта строк. Затем они делали это снова на следующей неделе. И через неделю. Это было плохо.

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

Итак, почему люди выполняют одну и ту же задачу снова и снова, вместо того чтобы остановиться, сделать шаг назад и потратить время на её автоматизацию?

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

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

Распространённое заблуждение №3: чтобы автоматизировать это, мне нужно изучить экзотические инструменты
Вы можете пойти по длинному пути, используя полноценный консольный язык, например, bash или Power-Shell, и систему автоматизации сборки. Если же вам нужно взаимодействовать с веб-сайтами, можно использовать такие инструменты, как Selenium.

Распространённое заблуждение №4: я не могу автоматизировать эту задачу, потому что не могу работать с этим форматом файлов
Если для части вашего процесса требуются документы Word, электронные таблицы или изображения, это действительно может быть сложно автоматизировать. Но действительно ли это необходимо? Можете ли вы использовать обычный текст? CSV файлы вместо таблиц? XML/JSON? Часто небольшая подгонка процесса под автоматизацию может дать хорошие результаты и значительно снизить трудозатраты.

Распространённое заблуждение №5: у меня нет времени разбираться в этом
Вовсе не обязательно зазубрить все команды bash. Учитесь на ходу. Когда у вас есть задача, которую, по вашему мнению, можно и нужно автоматизировать, узнавайте об инструментах автоматизации ровно столько, сколько вам нужно. И делайте это на ранних этапах проекта, когда обычно легче найти время. Как только вы добьетесь успеха, вы (и ваш начальник) увидите, что имеет смысл инвестировать в автоматизацию.

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Cay Horstmann
👍1
День семьсот шестидесятый. #ЧтоНовенького
Основные Запланированные Изменения в
ASP.NET в .NET 6
Первая превью версия .NET 6 вышла совсем недавно. Релиз планируется в ноябре, и .NET 6 будет LTS версией .NET. В .NET 6 используетcя открытый процесс планирования, поэтому можно посмотреть список основных изменений для этой версии на сайте https://www.themesof.net. Вот некоторые из основных функций ASP.NET Core, запланированных для выпуска .NET 6.
1. Горячая перезагрузка. Возможность быстрого обновления UI и кода запущенных приложений без потери состояния приложения для более быстрой и продуктивной работы разработчика.
2. Микро API. Упрощённое создание конечных точек API с гораздо меньшим количеством кода и трудозатрат.
3. Публикация в виде одного файла. Возможность создавать небольшие автономные высокопроизводительные приложения и сервисы.
4. AoT компиляция WebAssembly. Возможность предварительной компиляции кода .NET в приложениях Blazor непосредственно в WebAssembly при публикации для значительного повышения производительности во время выполнения.
5. Обновление поддержки SPA для бесперебойной работы с новейшими современными платформами JavaScript.
6. Гибридные настольные приложения Blazor. Возможность объединить лучшее из UI мультиплатформенных приложений Blazor и .NET для создания кроссплатформенных гибридных настольных приложений.
7. Добавление поддержки HTTP/3 и QUIC.

Что нового в ASP.NET в .NET 6 Preview 1?
1. Поддержка IAsyncDisposable в MVC
Теперь вы можете реализовать IAsyncDisposable на контроллерах, моделях страниц и компонентах представления для асинхронного удаления ресурсов.

2. DynamicComponent
Это новый встроенный компонент Blazor, который можно использовать для динамической визуализации компонента, указанного в параметре Type. Параметры могут быть переданы визуализируемому компоненту с помощью словаря:
<DynamicComponent Type="@someType"
Parameters="@myDictionaryOfParameters" />
@code {
Type someType = ...
IDictionary<string, object> params = ...
}

3. ElementReference - ссылка на соответствующие компоненты
Встроенные компоненты Blazor для пользовательского ввода (InputCheckbox, InputDate, InputFile, InputNumber, InputSelect, InputText и InputTextArea) теперь предоставляют удобную ссылку ElementReference на элемент ввода, что упрощает распространённые сценарии, как, например, установка фокуса.

4. Команда dotnet watch теперь по умолчанию запускает dotnet watch run.

5. Аннотации обнуляемых ссылочных типов
Обнуляемые ссылочные типы появились в C#8. В ASP.NET .NET 6 большинство новых API используют эти аннотации. Подробнее об обнуляемых ссылочных типах.

Источник: https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-1/
День семьсот шестьдесят первый.
DotNet Boxed. Дополненные Шаблоны для .NET Core
Команда dotnet new показывает доступные шаблонов проектов. В Visual Studio это можно выбрать в настройках «Показывать все шаблоны .NET Core в диалоговом окне Новый проект» (Show all .NET Core templates in the New Project Dialog). На основе этих шаблонов вы можете строить ваш новый проект.

Но шаблонов «из коробки» может быть больше. Представляю вам шаблоны dotnet-boxed. Установить это расширение можно, выполнив:
dotnet new --install Boxed.Templates

Теперь у вас появятся новые Boxed шаблоны:
- ASP.NET Core API Boxed
- ASP.NET Core GraphQL Boxed
- ASP.NET Core Orleans Boxed
- NuGet Package Boxed

На картинке выше настройка проекта создания NuGet пакета. Как видите, можно настроить тесты, GitHub Actions, .editorconfig, информацию о лицензии, стили кодирования и многое другое. Все эти скучные настройки сделаны за вас!

Сам проект на GitHub

Источник: https://www.hanselman.com/blog/dotnet-boxed-includes-prescriptive-templates-for-net
День семьсот шестьдесят второй. #ЗаметкиНаПолях #SQL
На третьем году существования канала я понял, что есть один язык, который я незаслуженно обходил вниманием. Восполняю упущение. Начинаю новую серию постов про SQL. Думаю, что основные основы читателям моего канала объяснять не надо (если надо, пишите в комментариях, что интересно), поэтому буду писать о «фишках». Проблема в том, что они различаются как по наличию в разных СУБД, так и по синтаксису. Поэтому буду стараться выбирать более-менее универсальные вещи и описывать концепцию, а не особенности синтаксиса.

Возвращение Данных из DML Запроса
Поначалу это может показаться странным, но возможность возвращать данные из DML - очень полезная функция.
- В запросе INSERT:
Наиболее распространённый вариант использования - получение автоматически сгенерированных значений. Например, ключей для создания записей в дочерних таблицах. Кроме того, возвращённые таким образом данные могут использоваться для аудита или логирования запросов.
- В запросе UPDATE:
Здесь выражение это используется не так часто, но всё же возможно его применение для получения значений по умолчанию, заданных в базе данных, либо для аудита запросов.
- В запросе DELETE:
Совсем редкий случай использования, в основном для целей аудита, либо, возможно, переноса данных в архивную таблицу, хотя так лучше не делать.

СУБД: Oracle, PostgreSQL, MariaDB
Выражение: RETURNING
Синтаксис:
INSERT INTO | UPDATE | DELETE FROM table …
RETURNING expression1 [INTO variable1]
[, expression2 [INTO variable2]] …;

Выражение INTO variable1 позволяет вставить возвращённое значение в переменную в хранимой процедуре. Возвращать значения можно как в переменные примитивных типов, так в целую строку, используя пользовательский тип:
my_row mytable%ROWTYPE;

RETURNING * INTO my_row;

Пример:
INSERT INTO users (firstname, lastname) 
VALUES ('Joe', 'Cool') RETURNING id;

СУБД: MsSQL
Выражение: OUTPUT
Синтаксис:
INSERT INTO | UPDATE | DELETE FROM table …
OUTPUT INSERTED.expression1 [INTO variable1]
[, DELETED.expression2 [INTO variable2]] …;

В MsSQL также можно обратиться к псевдотаблицам INSERTED и DELETED. В запросе UPDATEDELETED представляет заменяемое значение, INSERTED представляет новое значение поля. В запросах INSERT и DELETE используется соответствующая псевдотаблица.

Пример:
DELETE Sales.ShoppingCartItem
OUTPUT DELETED.*;

Источники:
-
https://app.pluralsight.com/library/courses/postgresql-data-manipulation-playbook/
-
https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql
День семьсот шестьдесят третий. #юмор
Сталкивались?)))
День семьсот шестьдесят четвёртый. #BestPractices
9 «Правил» Более Чистого Кода
Следующие 9 правил относятся ко всем объектно-ориентированным языкам. Изначально они были описаны в книге Джеффа Бея «The Thoughtworks Anthology» как «Object Calisthenics» (слишком мудрёные выражения, я даже не буду пытаться их перевести, чтобы вас не путать). Правила эти, как пиратский кодекс, скорее являются рекомендациями, чем строгими законами, и, конечно, подразумевают наличие исключений. Кроме того, со многими из них можно спорить (что и призываю вас делать в комментариях).

1. Один уровень вложенности на метод
Не плодите длинные методы, в которых условные операторы содержат циклы, содержащие вложенные циклы, содержащие условные операторы. Верхний уровень кода – нулевой, код внутри цикла или условного оператора – первый уровень вложенности. Всё! Код из более высоких уровней вложенности нужно выделить в отдельный метод. Исключение – однострочные операторы, return, continue и т.п. Это сильно улучшит читаемость кода.

2. Не используйте ключевое слово else
Спорное правило. Дело не в том, что нужно срочно очистить код от всех упоминаний else. Просто на самом деле в большинстве случаев можно обойтись без него:
- используя тернарный оператор:
var a = (x >= 0 ? "positive" : "negative");
- задавая изначальное значение переменной перед if:
var a = "negative";
if (x >= 0) a = "positive";
- используя return в блоке if (тогда код после блока if будет выполняться, как если бы он был в else)
и т.п.

3. Оборачивайте все примитивные типы и строки
Если коротко, то суть состоит в том, чтобы не использовать примитивные типы в качестве объектов домена. А использовать вместо этого специальные типы. Например, не использовать строку или число для почтового индекса. Индекс имеет определённый формат, а поэтому должен иметь и проверку правильности введённого значения, которую лучше реализовать внутри объекта индекса.

4. Полноправные коллекции
Это правило призывает создавать отдельный класс для коллекций из непримитивных типов. Например, Dictionary<Guid, Client>. На первый взгляд это простой словарь клиентов. Но ответьте на вопрос: позволено ли коду, использующему этот словарь, напрямую изменять его или изменять его элементы? Скорее всего нет. Таким образом эта коллекция сама должна стать полноправной сущностью домена со своими правилами обращения с элементами.

5. Одна точка на строку
За исключением паттерна Строитель, LINQ или Fluent API, не увлекайтесь длинными цепочками методов или свойств. Лучше разделить их на несколько переменных. Это поможет как чтению кода, так и отладке, т.к. можно будет остановить выполнение на любой строке, чего нельзя сделать в цепочке вызовов.

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

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

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

9. Не злоупотребляйте свойствами
Скажу честно, в оригинале это звучит как «Никаких геттеров/сеттеров/свойств», но это уже чересчур. Однако доля истины в этом правиле есть. Не позволяйте внешнему коду бездумно менять значения свойств класса. Если в классе есть счётчик, не дело внешнего кода произвольно менять его значение. Когда счётчик нужно увеличить, пусть внешний код вызывает специальный метод, который это делает.

Источник: https://youtu.be/gyrSiY4SHxI
День семьсот шестьдесят пятый. #Оффтоп
Почти год назад я писал про новую функцию языка C# - Генераторы Кода. И вот постепенно начали появляться интересные реализации, использующие их, например Mapster.

Но всё-таки до сих пор не было подробного объяснения, что это, как это всё работает, в чём плюсы и минусы, где их можно использовать и т.п. И вот недавно в открытый доступ выложили видео с последней конференции DotNext «Source Generators в действии» от Андрея Дятлова https://youtu.be/6QWZds35rGs

«В докладе вы узнаете не только о том, что скрывается за термином «Source Generators» и как его использовать, но и о том, как предоставить пользователю вашего генератора необходимую гибкость конфигурации и понятные сообщения о возникающих проблемах. Генерация кода по праву считается областью, в которой трудно понять, что пошло не так, покрыть программу тестами или взглянуть на полученный код под отладчиком. Это удерживает многих программистов от её использования, и в докладе Андрей расскажет о том, как с этим справляются генераторы. Тех, кто уже давно пользуется существующими технологиями метапрограммирования на практике, заинтересует, какие сценарии остались не поддержанными в C# 9 и сравнение новых возможностей с существующими технологиями (Fody, PostSharp, T4 и пр). Остались ли у них уникальные ниши и преимущества или же будущее за генераторами?»

Мне видео понравилось. Только имейте в виду, что требуется достаточно глубокий уровень знаний языка, чтобы более-менее понимать. Я частенько терял мысль.
День семьсот шестьдесят шестой. #ЧтоНовенького
Что нового в Visual Studio 2019 v16.10 Preview 1
В Microsoft объявили о долгосрочной поддержке релиза Visual Studio 2019 версии 16.9, а также о выходе первой предварительной версии 16.10. О новых функциях версии 16.9 я уже писал здесь и здесь, поэтому сегодня о 16.10, где есть пара интересных новинок.

1. Удаление неиспользуемых ссылок
Добавлена возможность удалить из проекта неиспользуемые ссылки на проекты и пакеты NuGet. Это можно сделать из контекстного меню проекта «Удалить Неиспользуемые Ссылки» (Remove Unused References). По умолчанию эта возможность отключена, но её можно включить в меню Инструменты > Параметры > Текстовый редактор > C# > Дополнительно (Tools > Options > Text Editor > C# > Advanced). Отметьте команду «Удалить неиспользуемые ссылки» (Remove Unused References). После выбора этого пункта контекстного меню откроется диалоговое окно, где вы сможете просмотреть все ссылки, которые будут удалены, и отметить те, которые вы хотите сохранить. См. рис. 1 ниже.

2. Упрощение выражений LINQ
Эти подсказки рефакторинга предложат вам, например, удалить лишний вызов метода .Where(), чтобы повысить производительность и читаемость. Подсказка появляется, если поместить курсор на выражение LINQ и нажать Ctrl+. См. рис. 2 ниже.

3. Новые варианты автозавершения
IntelliSense теперь будет предлагать среди вариантов завершения значения enum, когда тип известен, даже если вы не вводите название самого перечисления. Просто начните вводить название значения, и оно появится в подсказке. См. рис. 3 ниже.

Также в меню Инструменты > Параметры > Текстовый редактор > Дополнительно (Tools > Options > Text Editor > Advanced) можно настроить режим автозавершения только по Tab, автоматически (по точке, скобке и т.п.) или по последнему сохранённому значению.

Кроме того, новая команда «Умный Перевод Строки» (Smart Break Line) автоматически вставит фигурные скобки и поставит курсор между ними при нажатии Shift+Enter после объявления названия типа, метода, свойства, события и т.п. Повторное нажатие Shift+Enter уберёт скобки и добавит точку с запятой в конце строки.

4. Настройки стилей кодирования для пустых строк
Вы можете настроить обработку пустых строк в файле EditorConfig или в меню Инструменты > Параметры > Текстовый редактор> C# > Стиль кода > Параметры новых строк (Tools > Options > Text Editor > C# > Code Style > New line preferences). Например, вы можете настроить, допустимы ли несколько пустых строк подряд, допустим ли код сразу после закрывающей фигурной скобки блока и т.п. Для каждого параметра можно настроить, будет ли он исправляться при рефакторинге или выдавать предложение, предупреждение или ошибку. См. рис. 4 ниже.

Установить Visual Studio 2019 v16.10 Preview 1

Источник: https://devblogs.microsoft.com/visualstudio/vs2019-v16-9-and-v16-10-preview-1/
День семьсот шестьдесят седьмой. #Оффтоп #ЗадачиНаСобеседовании
Давненько у нас не было задач.

Допустим, вы ищете квартиру. Для простоты представим улицу в виде одномерного массива кварталов. Пусть у нас будет только одна улица в городе, идеально прямая, а расстояния между кварталами одинаковы и равны 1.
В каждом квартале есть подходящая вам квартира. Кроме того, в кварталах случайным образом расположены важные для вас объекты: магазин, тренажёрный зал, школа для ребёнка и т.п. Допустим, что они одинаково для вас важны. Идеальная для вас квартира находится квартале с наименьшим расстоянием до самого дальнего важного объекта. Обратите внимание: не с минимальной суммой расстояний до всех объектов, а с минимальным наибольшим расстоянием! Задача – найти такой квартал.

Кварталы даны в виде массива словарей (не пугайтесь, это для наглядности, и чтобы не создавать кучи сущностей 😊). В словаре ключ – строковое название объекта, и логическое значение есть он в квартале или нет. Например, вот так:
[
{{"gym",false},{"school",false},{"store",true}},
{{"gym",true },{"school",false},{"store",false}},
{{"gym",true },{"school",false},{"store",true}},
{{"gym",false },{"school",false},{"store",false}},
{{"gym",false },{"school",true},{"store",true}}
]
То есть, в первом квартале нет тренажёрного зала и школы, но есть магазин. Во втором есть только тренажёрный зал. В третьем – зал и магазин. И т.д.

Таким образом, в первом квартале дальше всего идти до школы - 4. А победителем получается квартал №4. Хотя там ничего нет, но из него до всех объектов расстояние 1.

Для простоты допустим, что кварталов всегда больше одного, и во всех кварталах заданы все нужные вам объекты (которых в принципе может быть сколько угодно). А при равенстве результатов можно выдать первый.

На этот раз у меня для вас есть даже шаблон проекта с тестами: https://github.com/sbzenenko/NetDeveloper/tree/main/ApartmentFinder
Всё, что вам надо сделать – реализовать метод Find(), принимающий массив кварталов и возвращающий индекс идеального квартала.

Вопросы и предложения оставляйте в комментариях. Через пару дней выложу решение с объяснением.
День семьсот шестьдесят восьмой. #ЗаметкиНаПолях
Обнуляемый null
Рассмотрим следующий код:
public class Person {
public string FirstName { get; }
public string LastName { get; } = null!;
public string? MiddleName {get; } = null;

public Person (string first,
string last, string? middle) {
FirstName = first;
LastName = last;
MiddleName = middle;
}
}

Что значит null! ?
Раньше оператор ! означал отрицание в логических выражениях. Но начиная с C#8 в языке допустимо использование обнуляемых ссылочных типов. Поэтому оператор ! приобрёл другое значение и стал называться null-снисходительным (null-forgiving).

Свойство MiddleName обнуляемое (string?), т.к. у человека может не быть отчества. Тогда:
Console.WriteLine(person.MiddleName.Length);
выдаст предупреждение, что MiddleName может быть null, а
Console.WriteLine(person.MiddleName!.Length);
не выдаст предупреждения из-за null-снисходительного оператора.

Таким образом программист сообщает компилятору, что он уверен, что здесь значение переменной не будет null.

Можно рассматривать операторы ? и ! как приведение типов
? = из необнуляемого в обнуляемый
! = из обнуляемого в необнуляемый

Например:
string? x;
? делает из необнуляемого string обнуляемый тип, поэтому можно использовать x = null.

string y;
Здесь y = null приводит к предупреждению компилятора, из-за присваивания null необнуляемому типу. Аналогично y = x приведёт к предупреждению, т.к. x может быть null. Однако y = x! не вызовет предупреждения, т.к. мы «гарантируем», что x не null.

ВНИМАНИЕ: оператор ! отключает только проверку компилятора на уровне системы типов. Во время выполнения значение может быть null. Поэтому использование null-снисходительного оператора может быть признаком плохого дизайна системы, поскольку он сводит на нет все усилия проверки на null-безопасность, которую выполняет компилятор.

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

Зачем тогда он нужен?
Существуют допустимые варианты использования, в которых использование является целесообразным:
- В некоторых (редких) случаях компилятор не может определить, что обнуляемое значение на самом деле не может быть null.
- Для упрощения миграции старого кода, не использовавшего обнуляемые ссылочные типы.
- В некоторых случаях вас просто не волнует, что что-то будет null.
- В тестах для проверки поведения кода при получении null.

Так что же такое null! ?
null! сообщает компилятору, что null не допускает значения null. Странно, правда? Но это то же самое, что и x! из примера выше. Литерал null допускает значение null по определению. Но, как мы узнали, обнуляемость любого типа можно переопределить с помощью оператора !.

Систему типов не волнует фактическое значении переменной во время выполнения. Её заботит только тип переменной времени компиляции. И в исходном примере свойство LastName (null!) не допускает значения null, что допустимо для системы типов.

Источник: https://stackoverflow.com/questions/54724304/what-does-null-statement-mean
День семьсот шестьдесят девятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
79. Используйте Анализаторы Кода
Ценность тестирования - вот что вбивают в головы разработчикам ПО с ранних этапов их пути в программировании. В последние годы рост модульного тестирования, разработки, основанной на тестировании, и agile методов свидетельствует о всплеске интереса к максимальному использованию тестирования на всех этапах цикла разработки. Однако тестирование - это лишь один из многих инструментов, которые можно использовать для улучшения качества кода.

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

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

Более сложные инструменты, такие как Splint для C, Pylint для Python или анализаторы Roslyn для .NET настраиваются. То есть вы можете выбрать, какие ошибки и предупреждения будет выдавать инструмент, с помощью файла конфигурации, в командной строке или в вашей IDE. В некоторых случаях можно писать аннотации для анализатора прямо в коде.

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

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

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Sarah Mount
День семьсот семидесятый. #Оффтоп #ЗадачиНаСобеседовании
Ответ на задачу про поиск квартиры.

Создадим двумерный массив для хранения расстояний. В строках будут кварталы, в столбцах объекты. При этом, если объект присутствует в квартале, отметим соответствующее расстояние как 0, если нет, для начала отметим его недостижимо большим значением, например, 999999 (ниже буду использовать *). Таким образом, для примера из задачи:
[
{{"gym",false},{"school",false},{"store",true}},
{{"gym",true },{"school",false},{"store",false}},
{{"gym",true },{"school",false},{"store",true}},
{{"gym",false },{"school",false},{"store",false}},
{{"gym",false },{"school",true},{"store",true}}
]
Первый квартал будет
1: * * 0

Теперь проходим вдоль массива кварталов. Если соответствующий объект есть, заполняем ячейку нулём, в противном случае заполняем её значением на 1 больше, чем в предыдущем квартале. Например, во втором квартале объект "store" будет иметь значение 1. Большие значения нас пока не интересуют, там будет значение <очень много>+1 (оставим их как *). Тогда второй квартал будет:
2: 0 * 1
И так далее:
3: 0 * 0
4: 1 * 1
5: 2 0 0

Теперь проходим массив кварталов обратно. На этом этапе:
1. Задаём значение расстояния как минимальное между существующим значением и значением на 1 больше, чем в предыдущем квартале. То есть, если, проходя в одну сторону, мы получили расстояние до объекта в 3 квартала, но он находится в следующем квартале, то, проходя в обратную сторону, мы зададим минимальное расстояние между 3 и 1 – 1. Аналогичным образом мы заменим все большие значение, обозначенные *.
2. Кроме того, рассчитав все расстояния в квартале, считаем максимальное из них.

5: 2 0 0 (макс: 2)
4: 1 1 1 (макс: 1)
3: 0 2 0 (макс: 2)
2: 0 3 1 (макс: 3)
1: 1 4 0 (макс: 4)

И, наконец, из максимальных значений выбираем наименьшее – 1 в 4м квартале.

Таким образом, нам нужно дважды пройти массив кварталов, в каждом перебрать все объекты. Если количество кварталов взять за M, количество объектов – за N, то сложность решения по времени O(2*M*N), сложность по памяти – O(M*(N+1)).

Код решения с тестами: https://github.com/sbzenenko/NetDeveloper/tree/main/ApartmentFinderSolution

PS: есть ещё нахождение максимума по N и минимума по M, которые сами по себе добавляют O(logM) и O(logN) по времени, но их можно находить параллельно с обратным прохождением массива.

Источник: https://youtu.be/rw4s4M3hFfs
День семьсот семьдесят первый. #ЧтоНовенького
Что Нового в EF Core 6 Preview 1
Ниже описаны некоторые из основных нововведений в предварительной версии EF Core 6.

1. Атрибут Unicode
Строковое свойство теперь можно сопоставить со столбцом, не поддерживающим Юникод:
[Unicode(false)]
public string Isbn { get; set; }
Поскольку номер ISBN не может содержать не-юникод символы, атрибут сообщит СУБД, что можно использовать не-юникод строку. Например, в SQL Server будет использован varchar вместо nvarchar.

2. Атрибут Precision
Теперь можно задать точность поля базы данных, указав количество цифр всего и после запятой, не используя непосредственно тип данных, поддерживаемый СУБД:
[Precision(precision: 10, scale: 2)]
public decimal Price { get; set; }

3. Атрибут EntityTypeConfiguration
Атрибут позволяет определять класс конфигурации сущности, позволяя вынести конфигурацию в отдельный класс, а не помещать её всю в OnModelCreating.
[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book {…}

При этом класс конфигурации должен реализовывать IEntityTypeConfiguration<T>:
public class BookConfiguration : 
IEntityTypeConfiguration<Book> {…}
ПРИМЕЧАНИЕ. Типы, помеченные атрибутом EntityTypeConfiguration не будут автоматически обнаруживаться в сборке. Типы сущностей должны быть явно добавлены в контекст EF.

4. EF.Functions.Random
EF.Functions.Random соответствует функции СУБД, возвращающей псевдо-случайное число от 0 до 1. Реализации уже готовы для SQL Server, SQLite, и Cosmos.

5. Проверка на null обязательных полей в in-memory базе
In-memory база данных теперь будет выбрасывать исключение при попытке сохранить null в свойстве, помеченном, как обязательное (например, атрибутом Required).
Эта проверка может быть отключена при необходимости:
….UseInMemoryDatabase("…")
.EnableNullabilityCheck(false);

Источник: https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-1/
День семьсот семьдесят второй. #ЗаметкиНаПолях
Автоматическая Жадная Загрузка Навигационных Свойств в EF Core
Обычно при загрузке навигационных свойств в EF Core вы вынуждены использовать метод Include, чтобы указать, какие навигационные свойства нужно вернуть в запрос. Это очень хорошая практика явно указывать, какие данные вам на самом деле нужны.

Например, допустим, что у нас есть есть два класса: контакт и его email адреса.
class Contact {
public int Id { get; set; }
public string Name { get; set; }
public ICollection ContactEmails { get; set; }
}
class ContactEmail {
public int ContactId { get; set; }
public Contact Contact { get; set; }
public string Email { get; set; }
}

При использовании подхода Code First это навигационное свойство будет без проблем обработано на основе соглашений. При запросе контактов, если бы мы хотим сразу получить и ContactEmails, нам пришлось бы написать что-то вроде этого:
_context.Contact.Include(x => x.ContactEmails)
.FirstOrDefault(x => x.Id == myContactId);
Это называется жадной загрузкой, потому что мы с сразу загружаем email адреса контактов, например, чтобы вернуть их пользователю или использовать где-нибудь еще в нашем коде.

Но что, если мы уверены, что каждый раз, когда мы загружаем контакты, нам сразу нужны их email адреса? Мы уверены, что никогда не будем использовать контакты без email адресов. Часто это характерно для навигационных свойств один-к-одному. Но даже в этом примере, возможно, везде, где мы показываем контакт, нам также нужно показать и его email’ы, поскольку они являются неотъемлемой частью модели.

Настройка AutoInclude
До EF Core 5 у вас действительно не было выбора, кроме как постоянно использовать Include. Однако сейчас ситуация поменялась, появилась функция AutoInclude:
builder.Navigation(x => x.ContactEmails).AutoInclude();

Строитель навигации используется довольно редко, поэтому не все знают о его возможностях. И стоит упомянуть, что AutoInclude() нельзя использовать на конфигурациях вроде HasOne() или HasMany(), он должен быть настроен обособленно, как в примере выше.

Вот и всё. Теперь каждый раз при получении данных Contacts их свойство ContactEmails будет заполнено без использования Include.

Игнорирование AutoInclude
Конечно, бывают случаи, когда вы настроили AutoInclude, а затем вам нужно написать запрос, не включающий навигационное свойство. К счастью, для этого есть хорошее расширение IQueryable:
_context.Contact.IgnoreAutoIncludes()
.FirstOrDefault(x => x.Id == myContactId);
Так мы можем отписаться от получения навигационного свойства, и не запрашивать из базы больше данных, чем нам нужно.

Источник: https://dotnetcoretutorials.com/2021/03/07/eager-load-navigation-properties-by-default-in-ef-core/