Windows forms net framework и net core
Улучшения и дополнения элементов управления Windows
Вот несколько примеров того, что мы получили от сообщества.
Новый элемент управления TaskDialog
Task dialog — это диалоговое окно, которое может использоваться для отображения информации и получения простого ввода от пользователя, но имеет больше функций, чем окно сообщения. Как и окно сообщения, оно форматируется операционной системой в соответствии с заданными вами параметрами.
Улучшения ListView
Элемент управления ListView хорошо знаком разработчикам Windows Forms, однако в нем отсутствовал API для легкого доступа к некоторым функциям, добавленным в Windows Vista, таким как сворачиваемые группы, групповые задачи, субтитры и нижние колонтитулы.
Улучшения FileDialog
FileDialog получил новый API: FileDialog.ClientGuid. Диалоговое окно файла Windows позволяет вызывающему приложению связать идентификатор GUID с постоянным состоянием диалогового окна. Состояние диалогового окна может включать такие факторы, как последняя посещенная папка, а также положение и размер диалогового окна. Обычно это состояние сохраняется в зависимости от имени исполняемого файла. При указании GUID приложение может иметь разные сохраняемые состояния для разных версий диалогового окна в одном приложении (например, диалогового окна импорта и открытого диалогового окна).
Улучшения производительности
Мы также расширили ряд API-интерфейсов, связанных с рендерингом (например, PaintEventArgs), с помощью интерфейса IDeviceContext, который, хотя и может быть недоступен напрямую разработчикам Windows Forms, позволяет нам обойти объект GDI+ Graphics и, таким образом, уменьшить выделение и увеличить скорость. Эти оптимизации показали значительное сокращение потребления памяти в путях перерисовки, в некоторых случаях экономия x10 при распределении памяти.
Вы можете взять тестовый проект здесь и самостоятельно проверить результаты, как и один из наших пользователей — Джереми Синклер:
И последнее, но не менее важное: мы расширили API TextRenderer, чтобы принимать перегрузки ReadOnlySpan char, потому что рисование и измерение текста — довольно распространенное действие. Это позволит значительно более эффективно отрисовывать текст, когда можно избежать выделения новых строк (нарезка другого ввода, построение массива символов на основе стека и т.д.).
Улучшения и исправления специальных возможностей
В течение последних нескольких лет команда обновляла Windows Forms SDK 20-летней давности, чтобы он соответствовал сегодняшним требованиям доступности и соответствию.
Мы также исправили несколько проблем, которые влияли на UX при использовании некоторых инструментов доступности. Например, мы переработали реализации специальных возможностей таким образом, чтобы доступ к AccessibleObject больше не приводил к преждевременному созданию элемента управления Handle, что, в свою очередь, обеспечивает более предсказуемое поведение элементов управления и позволяет избежать неожиданных сюрпризов в пользовательском интерфейсе.
Мы также улучшили и исправили поведение в нескольких элементах управления (таких как PropertyGrid и MonthCalendar), которые могли помешать инструментам специальных возможностей правильно перемещаться по пользовательскому интерфейсу или, в тяжелых случаях, вызывать сбой приложений.
Поддержка Visual Basic
Критические изменения
Предварительные требования Prerequisites
Предварительная версия конструктора WinForms в Visual Studio. Preview WinForms designer in Visual Studio.
В этой статье используется пример приложения Matching game. This article uses the Matching game sample app. Если вы хотите в точности выполнять инструкции данной статьи, скачайте и откройте это приложение в Visual Studio. If you want to follow along, download and open the application in Visual Studio. В противном случае используйте собственное приложение. Otherwise, use your own app.
Consider Consider
Удостоверьтесь, что ваше приложение подходит для переноса. Check that your application is a good candidate for migration.
Вы используете другую версию Windows Forms. You’re using a different version of Windows Forms.
Обновите пакеты NuGet, используемые в проекте. Update the NuGet packages used by your project.
Рекомендуется обновить пакеты NuGet до последней версии перед переносом. It’s always a good practice to use the latest versions of NuGet packages before any migration. Если ваше приложение ссылается на пакеты NuGet, обновите их до последней версии. If your application is referencing any NuGet packages, update them to the latest version. Убедитесь, что сборка приложения выполняется успешно. Ensure your application builds successfully. Если после обновления возникают ошибки пакетов, установите предыдущую версию пакетов, которая не нарушает работу вашего кода. After upgrading, if there are any package errors, downgrade the package to the latest version that doesn’t break your code.
Резервное копирование проектов Back up your projects
Пакеты NuGet NuGet packages
Чтобы перенести файл packages.config, выполните следующие действия. To migrate the packages.config file, do the following steps:
Будет создан отчет о сборке, из которого вы сможете узнать о любых проблемах переноса пакетов NuGet. A build report is generated to let you know of any issues migrating the NuGet packages.
Файл проекта Project file
Преобразуйте каждый проект в вашем решении. Convert each project in your solution. Если вы используете упомянутый выше пример приложения, то необходимо преобразовать проекты MatchingGame и MatchingGame.Logic. If you’re using the sample app previously referenced, both the MatchingGame and MatchingGame.Logic projects would be converted.
Чтобы преобразовать проект, выполните следующие действия. To convert a project, do the following steps:
В обозревателе решений найдите проект, который требуется перенести. In Solution explorer, find the project you’re migrating.
Щелкните проект правой кнопкой мыши и выберите Выгрузить проект. Right-click on the project and select Unload Project.
Щелкните проект правой кнопкой мыши и выберите Изменить файл проекта. Right-click on the project and select Edit Project File.
Скопируйте XML-код проекта и вставьте его в текстовый редактор. Copy-and-paste the project XML into a text editor. Копия нужна, чтобы было проще переместить содержимое в новый проект. You’ll want a copy so that it’s easy to move content into the new project.
Очистите содержимое файла и вставьте следующий XML-код: Erase the content of the file and paste the following XML:
Этот XML-код представляет базовую структуру проекта. This XML gives you the basic structure of the project. Однако в нем нет никаких параметров из старого файла проекта. However, it doesn’t contain any of the settings from the old project file. Используя старые сведения о проекте, скопированные ранее в текстовый редактор, выполните следующие действия. Using the old project information you previously copied to a text editor, do the following steps:
Скопируйте следующие элементы из старого файла проекта в элемент
в новом файле проекта: Copy the following elements from the old project file into the
element in the new project file:
Теперь XML-код в файле проекта должен выглядеть следующим образом: Your project file should look similar to the following XML:
, и вставьте их в новый файл после закрывающего тега
. Copy the elements from the old project file that contain
into the new file after the
Теперь XML-код в файле проекта должен выглядеть следующим образом: Your project file should look similar to the following XML:
не нужны дочерние элементы
elements don’t need the
and children, so you can remove those settings:
Ресурсы и параметры Resources and settings
Проекты Windows Forms также включают файлы проектов Windows Forms, такие как Properties/Settings.settings и Properties/Resources.resx. Windows Forms projects also include Windows Form project specific files, such as Properties/Settings.settings and Properties/Resources.resx. Может потребоваться перенести эти файлы. Они объявляются в исходном проекте. These files may need to be migrated they are declared in your original project.
Импортируйте конфигурацию для файла Settings.settings. Import the configuration for the Settings.settings file.
В проектах Visual Basic файл параметров проекта обычно по умолчанию находится в папке My Project, а в проектах C# — в папке Properties. Visual Basic projects typically use the folder My Project while C# projects typically use the folder Properties for the default project settings file.
В проектах Visual Basic файл ресурсов проекта обычно по умолчанию находится в папке My Project, а в проектах C# — в папке Properties. Visual Basic projects typically use the folder My Project while C# projects typically use the folder Properties for the default project resource file.
Visual Basic Visual Basic
Для проектов на языке Visual Basic требуется дополнительная настройка. Visual Basic language projects require extra configuration.
Добавьте параметр WindowsForms в элемент
: Add the WindowsForms setting to the
Импортируйте пространства имен, определенные в вашем проекте. Import the namespaces defined by your project.
. Copy the elements from the old project file that contain into the new file after the
Скопируйте параметры и из исходного проекта в элемент
: From the original project, copy the and settings to the
Перезагрузка проекта Reload the project
После преобразования проекта в новый формат в стиле пакета SDK перезагрузите проект в Visual Studio, выполнив следующие действия. After you convert a project to the new SDK-style format, reload the project in Visual Studio:
В обозревателе решений найдите преобразованный вами проект. In Solution Explorer, find the project you converted.
Щелкните проект правой кнопкой мыши и выберите Перезагрузить проект. Right-click on the project and select Reload Project.
Если проект не загружается, возможно, вы допустили ошибку в XML-коде проекта. If the project fails to load, you may have introduced a mistake in the XML of the project. Откройте файл проекта для редактирования и попробуйте найти и исправить ошибку. Open the project file for editing and try to identify and fix the mistake. Если не удается найти ошибку, попробуйте начать заново. If you can’t find a mistake, try starting over.
Изменение файла App.config Edit App.config
Если в вашем приложении имеется файл App.config, удалите элемент : If your app has an App.config file, remove the element:
Добавление пакета совместимости Add the compatibility package
Если файл проекта загружается правильно, но его компиляция завершается неудачно, появляется сообщение об ошибке, подобное приведенному ниже. If your project file is loading correctly, but compilation fails for your project and you receive errors similar to the following:
Измените файл проекта, добавив в него следующий элемент : Edit your project file and add the following element:
Тестирование приложения Test your app
После завершения переноса приложения протестируйте его! After you’ve finished migrating your app, test it!
.NET зоопарк под призмой NET Core
Stack technology
NET Standard
Cross Platform
Не буду заострять на этом ваше внимание, просто перечислю поддержку ОС для NET Core проектов:
Дополнительно поддерживает запуск под ARM процессоры на Linux и Windows.
Dependency
В рамках кросс-совместимости платформа для разработки приложений включает в себя модульную инфраструктуру. Она выдается через NuGet, и вы можете получить доступ к пакетным функциям, а не к одной большой сборке. Как разработчик вы можете создавать легкие приложения, содержащие только необходимые пакеты NuGet, что сделает вашу программу безопаснее и производительнее.
CSPROJ
Теперь давайте углубимся и посмотрим более подробно, что у нас под капотом в проектах. При создании нового проекта каждый из вас сталкивался с файлом MyProject1.csproj (название может отличаться). Этот файл отвечает за настройки компиляции данного проекта, зависимостей других проектов или либ (библиотек) и много чего ещё.
К сожалению на моём ПК этот файл не влезает полностью (там остались ещё референсы). А теперь взглянем как стало после переноса:
Performance & Improvements
• Измененный Random
• Измененный HttpClient
• Оптимизированы циклы
• Оптимизированы List, Array
• Оптимизированы Stream, MemoryStream
• И многое другое
В данной статье я не буду рассматривать все изменения. Это будет отдельной статьей. Но давайте рассмотрим небольшой пример на коллекции List:
Я прогнал его через benchmarkdotnet.org на обеих платформах. После тестов у меня вышли следующие результаты:
Core 2.2.4 x64 RyuJIT
Method: BenchmarkList
Mean: 370.1 ms
Error: 0.3761 ms
StdDev: 0.3518 ms
Framework 4.7.2 x64 RyuJIT
Method: BenchmarkList
Mean: 481.9 ms
Error: 1.210 ms
StdDev: 1.011 ms
Как видите, скорость работы существенно отличается(в разы) в пользу Core.
Microsoft старается не только дать разработчикам удобные инструменты для разработки, но и улучшает базовые вещи, которые приводят к улучшениям и оптимизациям ваших проектов.
Tier Compilation
Это возможность, благодаря которой среда выполнения более адаптивно использует компилятор JIT для повышения производительности при запуске и максимального увеличения пропускной способности.
Компилирует проект так быстро, насколько это возможно.
Оптимизирует наиболее частые методы.
Данный функционал приводит к тому, что ваш проект быстрее собирается и даёт вам почти аналогичную производительность. Мы тестировали данный функционал, и это шикарная функция для NET Core проектов, которая уменьшает время компиляции. Многоуровневая компиляция незначительно замедляет работу вашего приложения, я не советую включать ее на production сервере, но для отладки более чем актуальная функция которая экономит время программистов.
Заключение
Спасибо за внимание. Надеюсь, вам понравилось.
.NET Core vs Framework. Производительность коллекций
Мне стало интересно, какой прирост производительности можно ожидать от Core в самых базовых классах, которые максимально часто используются в коде. Например, коллекции List, Array и Dictionary.
Если вам тоже интересно, как и почему изменилась производительность основных коллекций в Core 3 — прошу под кат!
Бенчмарки
Также я прогонял все тесты на двух дополнительных машинах (на Haswell и Sky Lake), чтобы убедиться, что результаты тестов стабильны и воспроизводятся на другом железе.
Цикл for
Method | Runtime | Size | Mean | Error | StdDev | Ratio |
---|---|---|---|---|---|---|
IterateFor_Int | .NET 4.8 | 1000 | 565.09 ns | 0.191 ns | 0.127 ns | 1.00 |
IterateFor_Int | .NET Core 2.1 | 1000 | 451.14 ns | 0.236 ns | 0.156 ns | 0.80 |
IterateFor_Int | .NET Core 3.1 | 1000 | 451.08 ns | 0.143 ns | 0.085 ns | 0.80 |
IterateFor_String | .NET 4.8 | 1000 | 574.80 ns | 6.795 ns | 4.494 ns | 1.00 |
IterateFor_String | .NET Core 2.1 | 1000 | 460.86 ns | 3.771 ns | 2.494 ns | 0.80 |
IterateFor_String | .NET Core 3.1 | 1000 | 460.35 ns | 0.681 ns | 0.405 ns | 0.80 |
В Core JIT генерирует более эффективный код, чтение элементов из List в цикле for стало быстрее на
Цикл foreach
Method | Runtime | Size | Mean | Error | StdDev | Ratio |
---|---|---|---|---|---|---|
IterateForEach_Int | .NET 4.8 | 1000 | 1,574.5 ns | 2.73 ns | 1.81 ns | 1.00 |
IterateForEach_Int | .NET Core 2.1 | 1000 | 1,575.8 ns | 3.82 ns | 2.27 ns | 1.00 |
IterateForEach_Int | .NET Core 3.1 | 1000 | 1,568.1 ns | 0.61 ns | 0.40 ns | 1.00 |
IterateForEach_String | .NET 4.8 | 1000 | 8,046.3 ns | 36.51 ns | 24.15 ns | 1.00 |
IterateForEach_String | .NET Core 2.1 | 1000 | 6,465.0 ns | 15.26 ns | 10.09 ns | 0.80 |
IterateForEach_String | .NET Core 3.1 | 1000 | 5,886.3 ns | 14.65 ns | 9.69 ns | 0.73 |
Итерирование List с ссылочными типами через foreach стало быстрее на 27%, но для значимых типов ничего не поменялось. Здесь можно оценить, насколько foreach медленнее, чем for. Разница в их эффективности на Core составляет 3.5x (value types) и 12x (reference types), примерно также как и в полном фреймворке.
Чтобы протестировать метод без ресайза внутреннего массива в тесте используется конструктор List с заданной ёмкостью (capacity).
Method | Runtime | Size | Mean | Error | StdDev | Ratio |
---|---|---|---|---|---|---|
Add_Int | .NET 4.8 | 1000 | 2,006.5 ns | 11.65 ns | 6.93 ns | 1.00 |
Add_Int | .NET Core 2.1 | 1000 | 1,249.0 ns | 1.00 ns | 0.60 ns | 0.62 |
Add_Int | .NET Core 3.1 | 1000 | 1,260.9 ns | 5.88 ns | 3.89 ns | 0.63 |
Add_String | .NET 4.8 | 1000 | 3,250.8 ns | 53.13 ns | 35.14 ns | 1.00 |
Add_String | .NET Core 2.1 | 1000 | 2,816.8 ns | 37.26 ns | 22.18 ns | 0.87 |
Add_String | .NET Core 3.1 | 1000 | 2,538.2 ns | 30.55 ns | 20.21 ns | 0.78 |
Contains
Давайте возьмём негативный сценарий для метода Contains: будем искать элементы, которых нет в коллекции.
Method | Runtime | Size | Mean | Error | StdDev | Ratio |
---|---|---|---|---|---|---|
Contains_Int | .NET 4.8 | 1000 | 1,128.975 us | 5.4951 us | 3.6347 us | 1.00 |
Contains_Int | .NET Core 2.1 | 1000 | 456.040 us | 0.1437 us | 0.0950 us | 0.40 |
Contains_Int | .NET Core 3.1 | 1000 | 188.002 us | 0.1619 us | 0.0964 us | 0.17 |
Contains_String | .NET 4.8 | 1000 | 4,027.20 us | 9.479 us | 5.641 us | 1.00 |
Contains_String | .NET Core 2.1 | 1000 | 3,332.93 us | 2.156 us | 1.128 us | 0.83 |
Contains_String | .NET Core 3.1 | 1000 | 2,723.48 us | 2.460 us | 1.464 us | 0.68 |
Кстати, раньше я всегда думал, что метод Contains внутри вызывает IndexOf, но оказалось, что это верно только для Core. В полном фреймворке это разные методы, и работают они с разной скоростью.
List Methods Summary
Сводная таблица относительной производительности (ratio) основных методов List при N = 1000.
List Method | Type | .NET 4.8 | Core 2.1 | Core 3.1 | Details |
---|---|---|---|---|---|
Ctor | Int | 1.00 | 0.82 | 0.47 | Report |
Ctor | String | 1.00 | 0.90 | 0.92 | Report |
IterateFor | Int | 1.00 | 0.80 | 0.80 | Report |
IterateFor | String | 1.00 | 0.80 | 0.80 | Report |
IterateForEach | Int | 1.00 | 1.00 | 1.00 | Report |
IterateForEach | String | 1.00 | 0.80 | 0.73 | Report |
Add | Int | 1.00 | 0.62 | 0.63 | Report |
Add | String | 1.00 | 0.87 | 0.78 | Report |
Contains | Int | 1.00 | 0.40 | 0.17 | Report |
Contains | String | 1.00 | 0.83 | 0.68 | Report |
IndexOf | Int | 1.00 | 0.99 | 0.43 | Report |
IndexOf | String | 1.00 | 0.95 | 0.95 | Report |
Array Methods Summary
Подробно останавливаться на методах массива я не буду, поскольку List — это обертка над массивом.
Так что здесь я приведу таблицу относительной производительности Array при N = 1000.
Array Method | Type | .NET 4.8 | Core 2.1 | Core 3.1 | Details |
---|---|---|---|---|---|
Ctor | Int | 1.00 | 0.73 | 0.88 | Report |
Ctor | String | 1.00 | 0.75 | 0.84 | Report |
IterateFor | Int | 1.00 | 0.86 | 1.00 | Report |
IterateFor | String | 1.00 | 1.00 | 1.00 | Report |
IterateForEach | Int | 1.00 | 0.84 | 1.00 | Report |
IterateForEach | String | 1.00 | 1.00 | 1.00 | Report |
Здесь можно отметить, что как и прежде, цикл foreach для массива преобразуется в обычный for. Т.е. с точки зрения производительности для итерации массива нет разницы какой из циклов использовать.
Dictionary
Randomized Hash
Method | Runtime | Size | Mean | Error | StdDev | Ratio |
---|---|---|---|---|---|---|
Add_IntKey | .NET 4.8 | 1000 | 10.449 us | 0.0690 us | 0.0456 us | 1.00 |
Add_IntKey | .NET Core 2.1 | 1000 | 12.270 us | 0.0492 us | 0.0325 us | 1.17 |
Add_IntKey | .NET Core 3.1 | 1000 | 11.355 us | 0.0723 us | 0.0478 us | 1.09 |
Add_StringKey | .NET 4.8 | 1000 | 33.229 us | 0.0331 us | 0.0219 us | 1.00 |
Add_StringKey | .NET Core 2.1 | 1000 | 35.303 us | 0.1821 us | 0.1084 us | 1.06 |
Add_StringKey | .NET Core 3.1 | 1000 | 26.976 us | 0.1248 us | 0.0825 us | 0.81 |
Добавление в Dictionary с ключом String стало быстрее на 19%. В случае с Int ключом результат (ratio) зависит от размера: на 100 — 0.95, на 1’000 — 1.09, на 10’000 — 0.93. Отклонения небольшие, возможно, это просто «шум». На других машинах отклонения ещё меньше. Будем считать, что с ключом типа Int добавление элемента происходит примерно с той же скоростью.
GetValue
Method | Runtime | Size | Mean | Error | StdDev | Ratio |
---|---|---|---|---|---|---|
GetValue_IntKey | .NET 4.8 | 1000 | 10.916 us | 0.019 us | 0.013 us | 1.00 |
GetValue_IntKey | .NET Core 2.1 | 1000 | 10.985 us | 0.135 us | 0.089 us | 1.01 |
GetValue_IntKey | .NET Core 3.1 | 1000 | 9.424 us | 0.086 us | 0.056 us | 0.86 |
GetValue_StringKey | .NET 4.8 | 1000 | 31.622 us | 0.294 us | 0.175 us | 1.00 |
GetValue_StringKey | .NET Core 2.1 | 1000 | 31.787 us | 0.090 us | 0.047 us | 1.00 |
GetValue_StringKey | .NET Core 3.1 | 1000 | 23.572 us | 0.098 us | 0.058 us | 0.75 |
Получение элемента по строковому ключу стало быстрее на 25%, по Int ключу — на 14%. Однако, здесь есть зависимость от размера Dictionary. Чем меньше размер — тем больше Framework отстает от Core 3 и наоборот. На маленьких размерах Core 3 работает в 1.5 раза быстрей. При достижении размера в 10’000 производительность Core 3 падает до уровня Framework и даже чуть ниже (см. отчеты ниже).
В коде класса Dictionary слишком много изменений, чтобы однозначно сказать, какие из них больше всего повлияли на производительность.
Dictionary Methods Summary
Сводная таблица относительной производительности основных методов Dictionary при N = 1000.
Dictionary Method | Type | .NET 4.8 | Core 2.1 | Core 3.1 | Details |
---|---|---|---|---|---|
Ctor | Int | 1.00 | 0.95 | 0.62 | Report |
Ctor | String | 1.00 | 4.06 | 3.84 | Report |
Add | Int | 1.00 | 1.17 | 1.09 | Report |
Add | String | 1.00 | 1.06 | 0.81 | Report |
GetValue | Int | 1.00 | 1.01 | 0.86 | Report |
GetValue | String | 1.00 | 1.00 | 0.75 | Report |
ContainsKey | Int | 1.00 | 0.84 | 0.78 | Report |
ContainsKey | String | 1.00 | 0.99 | 0.73 | Report |
ContainsValue | Int | 1.00 | 0.54 | 0.54 | Report |
ContainsValue | String | 1.00 | 0.86 | 0.90 | Report |
Результаты
Как и ожидалось, почти все рассмотренные методы на Core 3 работают быстрее. Разница зачастую составляет 20-30%, а то и больше. Для таких базовых коллекций это отличный результат.
Код и детальные результаты всех тестов доступны на GitHub.
На сегодня Core практически догнал Framework по возможностям, а по производительности давно оставил его позади. Что касается ASP.NET Core — к третьей версии он вышел в топ самых производительных веб-фреймворков (топ-5 по последним тестам TechEmpower).
Материалы по теме
Читают сейчас
Редакторский дайджест
Присылаем лучшие статьи раз в месяц
Скоро на этот адрес придет письмо. Подтвердите подписку, если всё в силе.
Похожие публикации
Как я провел лето с C# 8
Вакансии
AdBlock похитил этот баннер, но баннеры не зубы — отрастут
Минуточку внимания
Комментарии 40
Что касается ASP.NET Core — к третьей версии он вышел в топ самых производительных веб-фреймворков (топ-5 по последним тестам TechEmpower).
Посмотрел ТОП, действительно пятое место, допустим у nginx на сях — 63, но… увидел надпись «kestrel» и сразу захотелось уточнить, что майкрософт не рекомендует выставлять kestrel в интернет. И сразу мне как-то показалось, что за такой высокий результат пришлось расплатиться именно порезанной безопасностью.
Таки у меня вопрос: за прошедшие пару лет что-то поменялось в безопасности kestrel или что в 2.1, что в 3.1 разницы особой нет?
Kestrel can be used by itself or with a reverse proxy server
На сегодня Core практически догнал Framework по возможностям, а по производительности давно оставил его позади. Что касается ASP.NET Core — к третьей версии он вышел в топ самых производительных веб-фреймворков (топ-5 по последним тестам TechEmpower).
Но пока что без дизайнера в студии, так что с миграцией я бы повременил. Чисто попробовать уже можно, да.
Xamarin.Forms вроде только для мобильных приложений? Для остальных тулкитов нет дизайнера (кроме Qt, там вроде можно использовать QtDesigner и потом подгружать *.ui). Есть еще uno platform. Я вообще хочу Blazor client-side с готовыми компонентами (или дизайнер какой-нибудь, не знаю HTML и все связанные технологии), заворачивать в CefSharp (привет аля электрон приложения).
Если вам тоже интересно, как и почему изменилась производительность основных коллекций в Core 3 — прошу под кат!
| Method | ElementsCount | Mean | Error | StdDev | Gen 0 | Allocated |
|—————— |————— |———-|———|———|——-|———-|
| MaxFromSortedSet | 10 | 43.54 ns | 0.434 ns | 0.384 ns | 0.0516 | 217 B |
| MaxFromSortedSet | 100 | 65.83 ns | 0.995 ns | 0.930 ns | 0.0631 | 265 B |
| MaxFromSortedSet | 1000 | 85.91 ns | 1.723 ns | 1.612 ns | 0.0745 | 313 B |
| MaxFromSortedSet | 10000 | 112.26 ns | 1.370 ns | 1.215 ns | 0.0899 | 377 B |
| MaxFromSortedSet | 100000 | 134.96 ns | 1.135 ns | 1.007 ns | 0.1013 | 425 B |
| Method | ElementsCount | Mean | Error | StdDev |
|—————— |————— |———-:|———-:|———-:|
| MaxFromSortedSet | 10 | 1.771 ns | 0.0676 ns | 0.0751 ns |
| MaxFromSortedSet | 100 | 4.124 ns | 0.1060 ns | 0.0885 ns |
| MaxFromSortedSet | 1000 | 6.175 ns | 0.1081 ns | 0.0903 ns |
| MaxFromSortedSet | 10000 | 8.426 ns | 0.1551 ns | 0.1375 ns |
| MaxFromSortedSet | 100000 | 11.245 ns | 0.1378 ns | 0.1151 ns |