.NET Standard

В этой статье собраны ответы на самые животрепещущие вопросы о .NET Standard.

Если вы понимаете английский, то самую свежую информацию из первых рук можно получить на github.com/dotnet/standard, в документации и в плейлисте .NET Standard на YouTube.

Ниже — моё понимание темы и комментарии.

.NET Standard — это вообще что?

.NET Standard — это спецификация, “бумажка”, "сертификат соответствия". Вы можете думать о .NET Standard как о списке интерфейсов, классов, свойств, методов, эвентов, которые обязаны присутствовать в той или иной конкретной реализации .NET (например, в .NET Framework, .NET Core, Xamarin, Mono и т.д.)

.NET Standard не содержит исполняемого кода, в нём есть только названия и сигнатуры, относительно которых работают компилятор и IntelliSense.

.NET Standard — это Target framework?

Да. В прикладном смысле .NET Standard используется в качестве Target framework при разработке библиотек:

Select .NET Standard as Target framework in Visual Studio 2017

.NET Standard — это как PCL?

Да. И у PCL (Portable Class Libraries), и у .NET Standard общая цель — позволить создавать библиотеки классов, совместимые с разными реализациями .NET, с множеством конкретных платформ.

.NET Standard использует более правильную стратегию с заделом на будущее.

PCL плохо масштабировались. Разработчик выбирал так называемый portable profile, из большого списка. В номерах профайлов было сложно ориентироваться, и с появлением новых платформ список приходилось всё более расширять. Чем больше платформ поддерживал PCL-профайл, тем меньшим получался общий знаменатель, тем меньше API было доступно разработчику. При этом понять, что доступно, а что нет, можно было только попробовав.

.NET Standard тоже построен на принципе общего знаменателя, но вместо фрагментации в основу положено наращивание этого знаменателя с каждой следующей версией:

Venn diagram comparing .NET Standard 1.0 vs 2.0

.NET Standard 2.0 примечателен тем, что в нём количество поддерживаемых API выросло почти в два с половиной раза по сравнению с 1.6:

.NET Standard API growth chart

С появлением .NET Standard, PCL объявлены устаревшим подходом.

.NET Standard гарантирует, что всё будет работать?

Нет. В рантайме можно получить PlatformNotSupportedException. К счастью, в основном, это касается естественных ограничений той или иной платформы.

Примеры: попытка работы с реестром Windows на Линуксе, AppDomain.CreateDomain в .NET Core.

Войдут ли в .NET Standard WinForms, WPF, классический ASP.NET?

Нет. Фреймворки/стеки для создания конкретных типов приложений в .NET Standard включены не будут. Рассуждайте об этом так: пригодится ли WinForms или ASP.NET MVC на мобильниках с Xamarin? А при разработке игр на Unity?

В .NET Standard включены только самые базовые вещи, такие как коллекции, работа с XML, ввод-вывод, tasks, threads, reflection, LINQ и так далее.

Существуют и “серые области”, наподобие System.Drawing, которые с одной стороны могут иметь смысл на всех платформах, с другой слишком завязаны на Windows с его GDI+. Подробности: github.com/dotnet/corefx/issues/20325.

Какие конкретные реализации .NET совместимы с .NET Standard?

Таблица совместимости и соответствия версий доступна на гитхабе и в документации.

Есть “платформы-фавориты”, на которые делается ставка. Это, конечно же, .NET Framework и .NET Core. Они первыми получают поддержку новых версий .NET Standard.

Mono, UWP и Xamarin тоже будут подтягиваться, но с некоторым запозданием.

Устаревшие платформы — Silverlight, Windows Phone и Windows Store 8.x, а также связанные с ними PCL-профайлы — застряли на отметке .NET Standard 1.2 и далее развиваться не будут.

Что такое Compatibility Shim?

Compatibility shim, она же прослойка совместимости, появившаяся в .NET Standard 2.0 — это совокупность специальных сборок-фасадов и MSBuild-овой магии, позволяющая использовать библиотеки, скомпилированные относительно .NET Framework в проектах, совместимых с .NET Standard, и наоборот.

Подробное описание от Immo Landwerth: .NET Standard - Under the Hood.

До .NET Standard 2.0 при попытке сослаться на библиотеку, собранную под .NET Framework, мы получали ошибку:

The type 'Object' is defined in an assembly that is not referenced.
You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

Происходит это оттого, что на уровне IL полный идентификатор типа включает имя сборки.

Для решения этой ситуации .NET Standard 2.0 предусматривает наличие специального варианта mscorlib.dll, полностью состоящего из “редиректов” (type forwarding):

.NET Standard 2.0 compatibility shim: mscorlib.dll facade mapped to netstandard.dll

И наоборот, проекты на базе .NET Framework (например, старые добрые Console Apps) могут ссылаться на сборки, “нацеленные” на .NET Standard. Достаточно добавить NuGet-пакет NETStandard.Library, который сделает некоторую магию, и после компиляции в bin вы обнаружите фасад netstandard.dll, наводящий мост до mscorlib.dll:

.NET Standard 2.0 compatibility shim: netstandard.dll facade mapped to mscorlib.dll

Описанное выше справедливо не только для mscorlib, но и для System.Core, System.IO, System.Xml и т.д.

Гарантируется 100% совместимость пересечение API между .NET Standard 2.0 и .NET Framework 4.6.1, за исключением одного нюанса, от которого на практике никто не должен пострадать.

Иными словами: в .NET Standard 2.0 вы найдёте большинство типов, которые привыкли видеть в стандартной библиотеке .NET Framework.

Как узнать, какие типы включены в .NET Standard?

Полный перечень API, а также отличия соседних версий стандарта в виде diff-файлов: github.com/dotnet/standard/tree/master/docs/versions

Ещё есть утилита .NET Portability Analyzer, с помощью которой можно проверить сборки на совместимость с .NET Standard и разными платформами.