company_banner

Расставим точки над .NET Core и .NET Standard

https://msdn.microsoft.com/en-us/magazine/mt842506?f=255&MSPPError=-2147217396
  • Перевод
.NET Core и .NET Standard — самые новые на сегодняшний день технологии .NET, поэтому совершенно неудивительно, что не только они, но и их отличия от платформы .NET Framework вызывают много вопросов. В этой статье я расскажу, что эти технологии из себя представляют и в каких случаях будет более логично выбрать каждую их.




Перед тем как углубляться в детали, обсудим среду .NET в целом и место, которое в ней занимают .NET Core и .NET Standard.

Платформа .NET Framework появилась 15 лет назад. Тогда в её состав входил только один стек технологий .NET, с помощью которого можно было разрабатывать приложения для ПК под управлением Windows и веб-приложения. С тех пор появились и другие реализации .NET, например, Xamarin для разработки мобильных приложений для iOS и Android и классических приложений для macOS.



Какое же место здесь занимают .NET Core и .NET Standard?


  • .NET Core — это самая новая реализация .NET. Это проект Open Source с версиями для нескольких ОС. .NET Core позволяет создавать кроссплатформенные консольные приложения, а также приложения и облачные службы ASP.NET Core.
  • .NET Standard — это набор базовых API (другое их название — BCL, библиотека базовых классов), которые должны поддерживаться во всех реализациях .NET. .NET Standard позволяет создавать библиотеки, подходящие для любых приложений .NET, вне зависимости от реализации .NET или операционной системы, в которой они выполняются.

.NET Core


.NET Core — это новая кроссплатформенная и полностью открытая реализация .NET. В её основе лежат технологии .NET Framework и Silverlight. Она оптимизирована для мобильных и серверных рабочих нагрузок, поскольку обеспечивает поддержку самодостаточных развёртываний XCOPY.

Чтобы лучше понять, что такое .NET Core, давайте попробуем разработать небольшое приложение для .NET Core. При этом мы познакомимся с новыми программами командной строки. Разрабатывать решения .NET Core можно в Visual Studio 2017, но раз уж вы читаете эту статью, я предположу, что с Visual Studio вы знакомы неплохо, и буду рассказывать в первую очередь о новых возможностях.

При создании .NET одним из главных приоритетов была высокая скорость разработки приложений для Windows. На практике это означает, что разработка .NET была неразрывно связана с Visual Studio. Безусловно, Visual Studio — замечательный инструмент. Он позволяет работать эффективно, а его отладчик — однозначно лучший из тех, которые мне доводилось использовать.

Но в некоторых случаях Visual Studio — не самый удобный вариант. Допустим, вы хотите поэкспериментировать с .NET, чтобы изучить C#. Для этого не хотелось бы скачивать и устанавливать IDE объемом в несколько гигабайт. Или, допустим, вы подключаетесь к компьютеру с Linux через SSH. Тогда работать через IDE вообще не получится. А может быть, вам просто нравится командная строка.

Для таких случаев создана отличная программа для работы в командной строке — .NET Core CLI. Основной компонент .NET Core CLI называется dotnet. Его можно использовать для решения практически любых задач разработки, в частности, для создания, сборки, тестирования и упаковки проектов. Давайте посмотрим, как это работает.

Для начала создадим и запустим консольное приложение Hello World (я буду использовать PowerShell для Windows, но в Bash для macOS или Linux все делается аналогично).

$ dotnet new console -o hello
$ cd hello
$ dotnet run
Hello World!

Команда dotnet new делает то же самое, что элемент меню File – New Project в Visual Studio. С её помощью можно создавать проекты различных типов. Используйте команду dotnet new, чтобы вывести список предустановленных шаблонов.

Давайте переместим часть логики в библиотеку классов. Для этого в дополнение к проекту hello создадим проект библиотеки классов.

$ cd ..
$ dotnet new library -o logic
$ cd logic

Здесь мы хотим описать логику, которая будет формировать сообщение Hello World. Поэтому изменим содержимое файла Class1.cs на следующее:

namespace logic
{
  public static class HelloWorld
  {
      public static string GetMessage(string name) => $"Hello {name}!";
  }
}

Переименуем файл Class1.cs в HelloWorld.cs.

$ mv Class1.cs HelloWorld.cs

Обратите внимание: обновлять файл проекта, чтобы отразить это изменение, не нужно. Новые файлы проекта в .NET Core уже включают все исходные файлы из каталога проекта. Поэтому при добавлении, удалении и переименовании файлов изменять проект больше не нужно. Это очень упрощает работу в командной строке.

Чтобы использовать класс HelloWorld, нужно добавить в приложение hello ссылку на библиотеку, в которой содержится логика. Для этого можно изменить файл проекта или воспользоваться командой dotnet add reference.

$ cd ../hello
$ dotnet add reference ../logic/logic.csproj

Теперь изменим файл Program.cs так, чтобы в нем использовался класс HelloWorld.

Обновление файла Program.cs для дальнейшего использования класса HelloWorld:

using System;
using logic;
namespace hello
{
class Program
{
static void Main(string[] args)
{
Console.Write("What's your name: ");
var name = Console.ReadLine();
var message = HelloWorld.GetMessage(name);
Console.WriteLine(message);
}
}
}

Чтобы собрать и запустить приложение, введите команду dotnet run.

$ dotnet run
What's your name: Immo
Hello Immo!

В командной строке также можно создавать тесты. Этот CLI поддерживает MSTest, а также популярную платформу xUnit. Давайте для примера воспользуемся xUnit.

$ cd ..
$ dotnet new xunit -o tests
$ cd tests
$ dotnet add reference ../logic/logic.csproj

Чтобы добавить тест, измените содержимое файла UnitTest1.cs, как показано ниже.

Добавление теста в файл UnitTest1.cs:

using System;
using Xunit;
using logic;
namespace tests
{
public class UnitTest1
{
[Fact]
public void Test1()
{
var expectedMessage = "Hello Immo!";
var actualMessage = HelloWorld.GetMessage("Immo");
Assert.Equal(expectedMessage, actualMessage);
}
}
}

Теперь можно запустить тесты с помощью команды dotnet test.

$ dotnet test
Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.

Рассмотрим более интересный пример: создадим простой веб-сайт ASP.NET Core.

$ cd ..
$ dotnet new web -o web
$ cd web
$ dotnet add reference ../logic/logic.csproj

Измените вызов app.Run в файле Startup.cs так, чтобы в нём использовался класс HelloWorld.

app.Run(async (context) =>
{
  var name = Environment.UserName;
  var message = logic.HelloWorld.GetMessage(name);
  await context.Response.WriteAsync(message);
});

Чтобы запустить тестовый веб-сервер, вновь введите команду dotnet run.

$ dotnet run
Hosting environment: Production
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Откройте в браузере URL-адрес, который был выведен в консоли (это должен быть адрес localhost:5000).

Сейчас структура вашего проекта должна соответствовать вот такой структуре.

Структура созданного проекта:
$ tree /f
│
├───hello
│ hello.csproj
│ Program.cs
│
├───logic
│ HelloWorld.cs
│ logic.csproj
│
├───tests
│ tests.csproj
│ UnitTest1.cs
│
└───web
Program.cs
Startup.cs
web.csproj

Чтобы упростить редактирование файлов в Visual Studio, создадим файл решения и добавим в него все проекты.

$ cd ..
$ dotnet new sln -n HelloWorld
$ ls -fi *.csproj -rec | % { dotnet sln add $_.FullName }

Как видите, .NET Core CLI — мощный и удобный инструмент, который покажется привычным даже тем разработчикам, которые никогда раньше не работали с .NET.

В этой статье мы использовали PowerShell в Windows, но в Linux и macOS все будет практически так же.

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

.NET Standard


Современные приложения часто приходится адаптировать к устройствам различных типов, а значит и к различным реализациям .NET. Клиенты воспринимают как должное доступ к хранящимся в облаке данным через веб-приложение с мобильного телефона или веб-браузер с ноутбука. В собственной инфраструктуре вам, скорее всего, захочется пользоваться программами командной строки и позволить сотрудникам управлять системой с помощью классических приложений. В таблице ниже показано, для решения каких задач подходят различные реализации .NET.
ОС Open Source Назначение
.NET Framework Windows Нет Создание классических Windows-приложений и веб-приложений ASP.NET для IIS.
.NET Core Windows, Linux, macOS Да Создание кроссплатформенных консольных приложений, а также веб-приложений и облачных служб ASP.NET Core.
Xamarin iOS, Android, macOS Да Создание мобильных приложений для iOS и Android, классических приложений для macOS.
.NET Standard Да Создание библиотек, которые можно использовать в любых реализациях .NET, в том числе .NET Framework, .NET Core и Xamarin.

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

Для решения этой задачи и создан .NET Standard. По сути он представляет собой спецификацию. В каждой версии .NET Standard определен некоторый набор API. Все реализации .NET, соответствующие этой версии, должны поддерживать все эти API. Эту систему можно рассматривать как еще один стек .NET, для которого можно создавать только библиотеки (но не приложения). Именно эту реализацию .NET следует использовать при создании библиотек, которые будут применяться в различных системах.

Возможно, вы задаетесь вопросом, какие именно API входят в .NET Standard. Если вы знакомы с платформой .NET Framework, то¬, наверное, знаете про библиотеку BCL — мы ее уже упоминали. BCL — это набор базовых API, не зависящих от инфраструктур пользовательского интерфейса и моделей приложений. В него входят простые типы, файловый ввод-вывод, сетевые API, API сериализации, XML и другое.

Каждый стек .NET реализует определенную версию .NET Standard. Обычно каждая новая версия реализации .NET реализует самую последнюю (на этот момент) версию .NET Standard.

Хорошая аналогия — язык HTML и браузеры. Представьте, что спецификация HTML — это .NET Standard, а различные браузеры — это реализации .NET (например, .NET Framework, .NET Core и Xamarin).

Вероятно, вы уже задаетесь вопросом, как можно пользоваться .NET Standard. На самом деле мы им уже воспользовались, когда создавали библиотеку с классом логики. Давайте взглянем на файл проекта внимательнее.

$ cd logic
$ cat logic.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

Сравним его с файлом проекта консольного приложения hello.

$ cd ..\hello
$ cat hello.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <ItemGroup>
    <ProjectReference Include="..\logic\logic.csproj" />
  </ItemGroup>

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

</Project>

Как видите, для параметра TargetFramework библиотеки логики задано значение netstandard2.0, а для соответствующего параметра консольного приложения — значение netcoreapp2.0. Параметр TargetFramework соответствует целевой версии реализации .NET. Таким образом, целевая реализация для консольного приложения — .NET Core 2.0, а для библиотеки — .NET Standard 2.0. Это значит, что к библиотеке логики можно обращаться не только из приложения .NET Core, но и из приложения для .NET Framework или Xamarin.

К сожалению, для большей части современных библиотек целевой реализацией является не .NET Standard, а .NET Framework. Конечно, .NET Standard в качестве целевой версии подходит не для всех библиотек, и это совершенно нормально. Например, целевой реализацией для библиотеки, в которой содержатся элементы управления Windows Presentation Foundation (WPF), должна быть .NET Framework, потому что компоненты пользовательского интерфейса не являются частью стандарта. Однако с большей частью библиотек общего назначения ситуация другая: для них целевой реализацией является .NET Framework просто потому, что на момент их создания .NET Standard еще не существовало.

В .NET Standard 2.0 содержится достаточно большой набор API для того, чтобы в подавляющей части библиотек общего назначения в качестве целевой реализации можно было использовать .NET Standard. В 70% библиотек, доступных сегодня в NuGet, используются только API, входящие в .NET Standard. Однако лишь немногие из них явным образом отмечены как совместимые с .NET Standard.

Чтобы разработчики могли использовать не только их, был добавлен режим совместимости. Если вы устанавливаете пакет NuGet, в котором нет библиотеки ни для вашей целевой платформы, ни для .NET Standard, то NuGet попробует использовать .NET Framework в качестве резервного варианта. Другими словами, вы можете обращаться к библиотекам .NET Framework так, как если бы для них в качестве целевой реализации был указан .NET Standard.

Давайте посмотрим, как это работает. В моем примере мы использовали популярную библиотеку коллекций PowerCollections, которая была создана в 2007 году. Она долго не обновлялась, и в качестве целевой платформы для нее по-прежнему указана .NET Framework 2.0. Добавим ее через NuGet в приложение hello.

$ dotnet add package Huitian.PowerCollections

Эта библиотека поддерживает дополнительные типы коллекций, которых нет в BCL. Один из них — тип Bag, не гарантирующий какого-либо порядка элементов. Изменим наше приложение hello так, чтобы в нем использовался этот тип.

Пример приложения с использованием PowerCollections:

using System;
using Wintellect.PowerCollections;
namespace hello
{
class Program
{
static void Main(string[] args)
{
var data = new Bag<int>() { 1, 2, 3 };
foreach (var element in data)
Console.WriteLine(element);
}
}
}

Если вы запустите программу, то увидите следующее:

$ dotnet run
hello.csproj : warning NU1701: Package 'Huitian.PowerCollections 1.0.0' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This may cause compatibility problems.
1
3
2

Что же произошло? Целевой реализацией для приложения hello является платформа .NET Core 2.0. .NET Core 2.0 является одной из реализаций .NET Standard 2.0, поэтому она поддерживает режим совместимости для обращения к библиотекам .NET Framework. Однако некоторые библиотеки .NET Framework в определенных реализациях .NET работать не будут. Например, это библиотеки, в которых используются API Windows Forms или WPF. NuGet не может об этом знать, поэтому он выдает сообщение с предупреждением о возможных проблемах.

Обратите внимание: это уведомление будет выводиться при каждой сборке. Иначе вы могли бы пропустить его при установке пакета или просто забыть о нем.

Конечно, неустранимые предупреждения, которые выводятся при каждой сборке, не могут не раздражать. Поэтому после проверки приложения вы можете отключить предупреждение, связанное с конкретным пакетом. Наше приложение работает правильно (корректно выводит содержимое созданной коллекции типа Bag), поэтому сейчас мы отключим это сообщение. Для этого изменим файл hello.csproj и добавим атрибут NoWarn в ссылку на пакет.

<PackageReference Include="Huitian.PowerCollections" Version="1.0.0" 
  NoWarn="NU1701" />

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

Еще новый набор инструментов позволяет создавать пакеты NuGet в процессе сборки проектов — библиотек классов. Таким образом можно легко предоставить доступ к библиотекам неограниченному числу пользователей (достаточно просто выложить их на nuget.org) или только сотрудникам вашей организации (для этого добавьте их в вашу ленту пакетов в Visual Studio Team Services или в MyGet).

В новых проектах поддерживается возможность задать несколько целевых платформ и выполнить сборку одного проекта для нескольких реализаций .NET. Это значит, что вы можете адаптировать библиотеку к конкретным реализациям .NET с помощью механизма условной компиляции (#if). Также вы можете создавать оболочки .NET Standard для API, относящихся к конкретным платформам. Но это уже совсем другая история.

Заключение


.NET Standard представляет собой спецификацию API, которые должны содержаться во всех реализациях .NET. Он делает семейство технологий .NET более организованным и позволяет разработчикам создавать библиотеки, которые можно использовать в любой реализации .NET. Этот стандарт заменяет библиотеки PCL в роли механизма создания общих компонентов.

.NET Core — реализация .NET Standard, оптимизированная для создания консольных приложений, веб-приложений и облачных служб с использованием ASP.NET Core. В состав соответствующего SDK входит несколько мощных инструментов, которые дополняют возможности Visual Studio, позволяя решать задачи разработки с помощью командной строки.

Подробная информация доступна на GitHub .NET Standard FAQ и сайте .NET and C# — Get Started in 10 Minutes.


P.S. Спасибо Косте Кичинскому (Quantum Quintum) за иллюстрацию к этой статье.
Microsoft 355,20
Microsoft — мировой лидер в области ПО и ИТ-услуг
Поделиться публикацией
Комментарии 56
  • –35
    Ваш hello world просто омерзителен визуально и эстетически. Почему? Потому что вы, например, решив не реализовывать функции в языке, создали дырявую абстракцию. Как запускается программа? В классах ищется статический метод main (который на самом деле замаскированная функция), и запускается. Но нам говорили, что классы могут иметь собственные методы и метод одного класса не влияет на метод другого класса. Но нет, из-за гениального решения использовать «первый попавшийся» main из первого попавшегося класса, язык запрещает реализовывать метод main более чем в одном классе.

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

    • +19
      Но нет, из-за гениального решения использовать «первый попавшийся» main из первого попавшегося класса, язык запрещает реализовывать метод main более чем в одном классе

      1) Язык c# и платформа не запрещает использовать статический метод Main в более чем одном классе.
      2) Статический Метод Main, если ничего дополнительно не делать, вызовет ошибку компиляции только в консольном приложении или Windows Application, в своих библиотеках, Вы можете хоть миллион методов Main накопипастить.
      3) Чтобы создать второй и последующие методы Main в консольном приложении или в windows (там где должна быть точка входа), можно создать ее и зайти в свойства сборки и указать какую EntryPoint использовать по-умолчанию. Или компиляцию запустить с флагом /main.

      А в общем RTFM.

      • +6
        Вы можете создавать несколько классов с main методами. И даже можете называть эти методы не Main, но тут уже надо в IL лезть)
        А так я не понял в чем проблема. Обычная convention over configuration упрощающая жизнь.
        • –23
          Это упрощает жизнь? Ох, ну тяжкая у вас жизнь, если это — упрощение.
          • +6
            Если это не троллинг, то я искренне не могу понять в чем тут проблема!
            • –7
              Это не троллинг. Это искреннее инженерное возмущение кривым решением.

              Можете ли вы объяснить причину, почему в языке надо было сначала запрещать наличие функций, а потом приделывать «искать статический метод с магическим именем внутри всех классов»? Лично я вижу в этом лишь набор пуризма (функции нинада) подпёртый костылями (но как-то запускать приложение таки нужно).

              В чём мысл вообще объявлять статический метод внутри класса, если он вызывается как функция? Может, лучше, просто оставить функции в покое?
              • +8
                Нет это троллинг.
                Вам уже объяснили, что в языке c#, да и в .net нет запрета на наличие функций Main.
                В чём мысл вообще объявлять статический метод внутри класса, если он вызывается как функция

                Это запрет на использование глобальных функций в языке c#. Каждая вызываемая функция должна относится к инстансу или типу.
                На других языках, при взаимодействии с CLR такого требования нет. Например f#
                [<EntryPoint>]
                let main argv = 
                    System.Console.WriteLine "hello world"
                    0 // return an integer exit code
                

                Как видно, нет никаких статических классов, только чистая функцианальщина.
                • +3
                  Можете ли вы объяснить причину, почему в языке надо было сначала запрещать наличие функций

                  Исторически — потому что начинали язык как клон Java, где было принято аналогичное решение. Идеологически — потому что компилятор C# не использует заголовочные файлы, а потому любая функция была бы видна в проекте отовсюду, что идет вразрез с нормальными архитектурными практиками.


                  Ну а практически — какая разница? Объявление класса-контейнера функций — это всего лишь три строчки кода. Лично мне одинаково комфортно писать как на языках с глобальными функциями, так и на языках без них.


                  Ну а про "а потом приделывать" я уже писал в другом месте, не буду повторяться.

                  • 0
                    Если не запретить объявлять функции в глобальном контексте, то какой-нибудь баран обязательно будет так делать, очевидно же.
            • +11
              Столько гнева вместо того, чтобы разобраться в обсуждаемой теме.

              С практической точки зрения проблема ничтожна. Даже если у вас в программе возникают два статических метода с подходящими для точки входа сигнатурами (что крайне маловероятно) — достаточно выбрать нужный в настройках проекта:



              Возможно, с эстетической точки зрения наличие «магического» метода действительно выглядит не очень элегантно — с этим согласен. Однако ради этого плодить сущности, добавляя в язык отдельную концепцию «функций» — решение еще хуже.
              • –8
                Именно в этом месте я вижу пуризм, помноженный на костыли. Одним «ещё хуже», другие «выкручиваются». На выходе имеем нелогичную конструкцию с магическим заклинанием. «Потому что это лучшее что мы сумели придумать».
                • +8
                  Пуризм — это считать весь стек технологий непригодным для использования, потому что точка входа указывается непривычным для вас образом.
                  • –16
                    Нет пуризм — это считать, что весь стек непригоден, потому что этого стека как такового не существует. А существует огород (C#), три песочницы (Framowork, Mono, core) и куча костылей (Standard) чтобы хоть как-то можно выкрутиться. А еще компания которая все это развела педалит свои ключевые (она считает их ключевыми) продукты исключительно только под один из огородов (ASP.Net netcore).

                    Это все помои технологические. Фрагментация без явно выраженного плана эту фрагментацию прекратить.

                    Не надо про пуризм — мы Майкрософт-технологии тут обсуждаем — от говна бы отмыться…
                  • +1

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

                    • +7
                      > Одним «ещё хуже», другие «выкручиваются»
                      Да кому хуже? Кто выкручивается? Жертвы есть? Пострадавшие?
                    • +1
                      Тоже не вижу никакой проблемы с Main, но вообще «отдельную концепцию функций» — это как раз то, чего очень нехватает в C#, IMHO. Вот обожаю функциональное программирование (и C#) и рад видеть, как его в C# становится всё больше и больше, но постоянно ловлю себя на мысли «как здорово бы было если бы можно было просто взять и описать функцию в отдельном файле, не создавая под неё класс». Бесит необходимость создавать длиннющие статические классы со статическими методами.

                      Мне кажется иногда добавить «лишнюю» сущность лучше, чем использовать имеющуюся сущность (в данном случае классы) не по назначению (не для описания типов реально использующизхся объектов).

                      При этом на уровне компилятора/CLR для функций вовсе не надо создавать новую сущность, можно сделать как в Scala: там функция — это просто объект с методом по имени «apply».
                      • 0
                        >>можно было просто взять и описать функцию в отдельном файле
                        А что мешает вынести отдельную сборку на F# и там вводить эти функции? А потом просто подключать reference. В Visual Studio это делается за «пару кликов».
                        • +1

                          Да проще уж статический класс завести.

                        • +2
                          В функциональном программировании функции тоже не в вакууме висят — они группируются в модули. Считайте, что static class — это такой своеобразный синтаксис для объявления модуля, а потом используйте using static — и будет полное подобие функций.
                          • 0
                            а потом используйте using static — и будет полное подобие функций

                            О! Прикольно. Не знал про такое. Спасибо.
                          • +2
                            Для людей, пишущих функции в глобальном скоупе, явно предусмотрен отдельный круг ада.
                            • +2

                              … глобальный круг ада.

                            • 0

                              Такая сущность на уровне CLR уже есть:
                              В каждой сборке уже есть секция Module, в которой могут храниться глобальные методы (функции).
                              Например, разрабатывая на чистом на IL, вы можете создать сборку с функциями без статического класса-контейнера.
                              Но обязательность поддержки этой возможности не входит в требования CLS, а в C# эту возможность разработчики не включили.

                          • +4
                            Все абстракции к чертям под хвост — какие именно?
                            Как запускается программа? — а как она запускается на языке C++? Или Асме.
                            Язык запрещает реализовывать метод main более чем в одном классе? — Язык ещё запрещает строки изменять и пробелы в именах переменных использовать, чудовищно правда?
                            • –13
                              На С++ оно запускается совершенно гармонично. Запускается функция main. Которая (в силу синтакисиса языка) единственная в основном namespace'е. Никаких дополнительных соглашений и копаний в чужом грязном белье. main может быть один не потому, что «копающемуся в белье трудно разобраться», а потому что имена функций должны быть уникальными в заданном namespace.

                              На ассемблере всё ещё проще: после отработки ELF loader'а запускается код по адресу entry point AT_ENTRY. Подробнее тут: lwn.net/Articles/631631

                              Заметим, си и libc гармонично это скрывают от пользователя не вызывая никаких разрывов абстракций и странных инстроспекций.
                              • +2
                                А в шарпе запускается static класс у которого есть Main, при этом можно иметь много других классов у которых так же будет эта функция но нужно выбрать любой из них как объект для запуска. В чём проблема? В том что фреймворк даёт возможность выбора?

                                Причём тут разрыв абстрации и запуск приложения?
                                • +11
                                  Которая (в силу синтакисиса языка) единственная в основном namespace'е

                                  В с++ такие же костыли. В основном namespace я могу объявить несколько функций с одним и тем же названием, но с разным количеством аргументов. А вот с функцией main такое не прокатит. Функция Main должна быть одна и перегружать ее нельзя — прямой отступ от спецификации — считай костыль.
                                  int main()//точка входа
                                  {
                                  	printf("hello world from main");
                                      return 0;
                                  }
                                  
                                  int test()//норм
                                  {
                                  	return 0;
                                  }
                                  
                                  int test(int l)//норм
                                  {
                                  	return l;
                                  }
                                  
                                  int main(int test)//упс - error C2731: 'main': function cannot be overloaded
                                  {
                                  	printf("hello world from main with parameters");
                                  	return 0;
                                  }
                                  
                                  • +6

                                    Ну-ну. Вообще-то, в С++ существует такая штука как перегрузка функций. А еще — статические функции. А еще — анонимные пространства имен (как способ сделать скопом кучу функций статическими). Ну и что теперь компилятору делать когда в программе есть 5 функций main, одна из которых не принимает параметров, вторая принимает (int, char**), третья — (int, chat const**), а еще две — статические в разных модулях?..


                                    Ах да, совсем забыл, для функции с именем main дополнительные языковые возможности запрещены. Вот это и есть настоящий костыль, когда все функции равны но некоторые равнее других.


                                    В C# же Main — это обычный статический метод. С которым можно сотворить что угодно из того что допустимо творить со статическими методами.


                                    Например, в C# можно за пару минут сделать обертку вокруг другого исполнимого файла, которая выполнит некоторую инициализацию а потом передаст управление на старую точку входа (в эту пару минут я включил запуск студии и создание проекта но не включил написание полезной нагрузки). В Си или C++ же надо ковыряться с настройками линкера, что требует специальных знаний.

                                    • +4
                                      Ах да, совсем забыл, для функции с именем main дополнительные языковые возможности запрещены.
                                      Зато добавлены новые! В стандартном C++ функция main обязана возвращать int (по станларту объявить её void, как в старом добром Borland C++ 3.1 — нельзя), но при этом оператор return — можно и не использовать (тоже по стандарту).

                                      Красота, правда?
                                • 0
                                  И в Java и в C# можно явно указать класс, в котором функция main/Main будет входной точкой программы. Никакого запрета нет. Я вот специально ввёл в Гугле «c# main», первая же ссылка выдала документацию, где на первой странице это подробно описано. Впрочем некоторых сейчас реально банят в Гугле.
                                • +2
                                  Лучше бы рассказали как оно устроено и работает внутри. Подобной информации в интернете уже море.
                                  • +3
                                    Поддерживаю. А так хорошо бы по .NET Core иметь книгу уровня CLR via C# Рихтера.
                                    • +3

                                      Через TypeForwardedTo оно работает. В каждом поддерживающем netstandard фреймворке (либо в поставляемой с SDK dll-ке в случае фреймворков < 4.7) лежит netstandard.dll в котором что-то типа этого:


                                      Скрытый текст


                                      Что касается .NET Core, то там всё тот же самый CLR с теми же самыми JIT-ом и GC, просто выложили в опенсурс и слой абстракции от платформ подпилили.

                                    • +1
                                      Меня в этой теме с подключением любой библиотеке к core проектам смущает то, что все падения переходят в рантайм, если я правильно понял. Хотелось был все таки ловить несовместимость либы со стандартом еще на шаге компиляции. Даже в примере PowerCollections проверена только одна коллекция в одном сценарии. Замучаешься проверять, что вся либа не упадет, обратившись к недоступному api.
                                      • 0

                                        О каком недоступном api речь? Если платформа поддерживает некоторую версию .net standart — то она поддерживает ее всю, целиком.

                                        • 0
                                          Но ведь .netframwork не поддерживает полностью .net standart и тем не менее я могу зарефференсить его из coreapp. Может произойти такое, что старая библиотека использует в каких то методах, к примеру, msmq api, но я использую его в coreapp? Она работает нормально, но при вызове некоторых методов, которые используют msmq api, она падает в рантайме, т.к. .net standart нет msqm. Да и вообще запущенно приложение на линуксе было.

                                          Возможен ли такой сценарий или я что то не понял в механизме рефференса пакетов?
                                          • 0

                                            Как это .net framwork не поддерживает полностью .net standart? А на основе чего тогда .net standart делался?


                                            Возможен ли такой сценарий или я что то не понял в механизме рефференса пакетов?

                                            Если в .net standart нет msqm — то библиотека которая использует msqm не сможет быть собрана под .net standart, а у несуществующей библиотеки никаких проблем в рантайме быть не может :-)

                                            • 0
                                              .NET Core 2.0 является одной из реализаций .NET Standard 2.0, поэтому она поддерживает режим совместимости для обращения к библиотекам .NET Framework. Однако некоторые библиотеки .NET Framework в определенных реализациях .NET работать не будут. Например, это библиотеки, в которых используются API Windows Forms или WPF.


                                              Ну т.е. как понимаю в .net standart есть подмножество классов из полного .net framwork. Есть некоторые классы(windows only) которых нет в .net standart. Но при этом нет запрета и проверки реффать .net framwork из dotnetcoreapp.
                                              • 0

                                                А, ну так предупреждение-то выдается.

                                                • 0
                                                  Ну вот это мне и не нравится, лишь предупреждение, и возможность падения в рантайме. Я так понимаю выход это взять исходники и запихать их в .net standart либу. Если скомпилилтся, значит все ок. Нет будет видно с какими api проблема.
                                              • 0
                                                Если в .net standart нет msqm — то библиотека которая использует msqm не сможет быть собрана под .net standart

                                                Да, но речь же о использовании старых библиотек которые, судя по статье, можно зарефференсить и в core. И выдастся лишь предупреждение.
                                            • 0
                                              Не совсем. Начиная с версии 2.0 целевая платформа может не поддерживать какую-то часть API и просто выкидывать PlatformNotSupportedException. Например: UWP не поддерживает создание AppDomain.
                                            • 0

                                              Нугет честно предупреждает, что задействован слой совместимости. Чтобы достоверно узнать, будет работать либа или нет, на неё надо натравить анализатор (брать либо в студийном маркетплейсе, либо консольную версию тут). Он быстро расставит точки над ё и скажет, всех ли типов хватает.

                                          • 0
                                            А как со всей этой радостью соотносятся winrt-компоненты? Так и придется юзать этот огрызок winmd, чтобы из js получить доступ?
                                            • 0
                                              А как winrt компоненты вообще относятся к дотнету? Это виндовое api которое можно дергать из дотнета, а можно из js.
                                            • +2
                                              Мне кажется главная сила виндового .Net — замечательный фрэймворк WPF и неплохой (если не сравнивать с WPF, конечно) фрэймворк WinForms, а главная трагедия .Net в целом — отсутствие стандартного кроссплатформенного GUI-фрэймворка. Если бы в стандарте .Net Core появился какой-то аналог WPF, одинаково работающий под Windows, Linux и Mac — это был бы фуррор, IMHO.
                                              • +3

                                                Попробуйте Avalionia :)

                                                • –2
                                                  Что-то судя по скриншотам всё очень плохо.
                                                • 0
                                                  А как же победа web'а? :)
                                                  Я вот очень надеюсь, что мне больше никогда не придётся писать UI ни на чём, кроме typescript :)
                                                  • +6
                                                    А я искренне надеюсь, что мне никогда не придется писать UI на яваскрипте и его потомках.
                                                  • 0
                                                    кросплатформа == OpenGL. MS так долго пилил DirectX и тут вы предлагаете такой поворот.
                                                    хотя конечно winForms крос-гуи это был бы лютый вин. дали бы Электрону прикурить
                                                    • 0
                                                      WinForms крос-гуи давно уже реализован в проекте Mono
                                                  • –7

                                                    Приветствую всех!
                                                    Сообществу в связи с полным отсутствием комьюнити по .core интересные конкретные примеры на тему "Как сделать первый сайт", первое приложение для десктопа… Ой, или нельзя? Так для чего же тогда сделан .core, позвольте спросить? Где его преимущества?

                                                    • 0
                                                      Странно, почему .NET Framework обозначен как не опенсорс? Вот же: referencesource.microsoft.com. И это не .NET Core, его исходники отдельно: github.com/dotnet/corefx.
                                                      • 0

                                                        Reference Source нельзя взять и скомпилировать чтобы собрать свой .NET Framework.

                                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                      Самое читаемое