Как создать или использовать готовые Shims для переноса из .net framework на .net core / standard? - PullRequest
0 голосов
/ 12 сентября 2018

Как создать или использовать готовые Шиммы для .net framework 4.6.1 элементов для их портирования (от .net framework 4.6.1) до .net core 2.0 / .net standard 2.0?


Некоторые классы интереса: , было бы неплохо иметь прокладки для таких классов, как:

System.Windows.Threading.Dispatcher

или

System.ComponentModel.ItemPropertyInfo.Descriptor

даже

System.Windows.Controls.MenuItem

и многие другие ...


Контекст:

Приложение (код) не на 100% хорошо организован.Бизнес-логика не отделена на 100% от логики пользовательского интерфейса.Ответ «сначала сделай рефакторинг», безусловно, хороший ответ.Но в моем случае все не на 100% так, как должно быть в идеале.


Примерный пример, попробуйте сделать это вручную:

System.Windows.Threading.Dispatcherне реализовано в Core 2.0.

Можно попытаться добавить:

public enum DispatcherShimPriority
{
    Background
    //...
}

public interface DispaicherShim
{
    void Invoke(Action action, DispatcherShimPriority prio);
    void BeginInvoke(Action action, DispatcherShimPriority, prio);
}

С последующими двумя реализациями этого интерфейса:

public class DispatcherCore: DispaicherShim;

и

public class DispatcherFramework: DispaicherShim;

За ним следует класс (давайте назовем его Shims) в многоцелевом проекте:

public static DispaicherShim CreateDispatcher()
{
#if NETCOREAPP2_0
    return new DispatcherCore();
#else
    return new DispatcherFramework();
#endif       
}

В результате получается шим, который можно использовать в различных API.

Это правильный подход?


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


Мне известно о пакете Microsoft.Windows.Compatibility.Вопрос скорее связан с портированием, когда WPF связан со многими элементами, специфичными для wpf.Эти элементы не находятся в пакете Microsoft.Windows.Compatibility, но, к сожалению, они используются во всех моих сборках, которые являются кандидатами для перенаправления на .Net Core 2.0.Я имею ввиду шимминг тех классов, которых нет в Microsoft.Windows.Compatibility.

Хорошо, у нас есть это Microsoft.Windows.Compatibility.Shims, но я не уверен, что это полезно в моем случае;особенно после прочтения следующего текста :

Microsoft.Windows.Compatibility.Shims : этот пакет предоставляет услуги инфраструктуры и на него нельзя ссылаться непосредственно из вашегокод ....


Upd: подчеркивая, что конечная цель - .net core 2.0

Upd2: всезадача состоит в том, чтобы перенести основную часть приложения WPF на .net core (оставив работающее приложение WPF ) для потенциального веб-клиента .Основная часть содержит .net framework элементов, которые не реализованы для .net core.

Upd3: Пару слов о полной стратегии: Более полная стратегия - это общие проекты, сначала Подход в этой статье (#if) .В моей стратегии есть два основных шага: один - постепенно портировать код, начиная с базовых библиотек и заканчивая топовыми библиотеками, но с интенсивным использованием заглушек и PlatformNotSupportedException s.Вторым шагом является переход от верхних библиотек к базовым библиотекам, заменяющим заглушки и исключения реализациями ядра .net, по требованию (!) - нет необходимости заменять все заглушки и исключения.

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

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

Переход от Standard .Net к .Net Core - это не просто обновление, его можно назвать переходом на новую платформу с учетом того, как все складывается вместе.Переход на ядро ​​.Net означает изучение и создание новой инфраструктуры, в которую можно скопировать существующий код.

Из-за больших различий между .Net core 1, 1.1, 2.0 и 2.1 форма процесса миграции сильно изменилась.Таким образом, не существует одного размера, подходящего для всех «прокладок», и наличие какой-либо обертки или инструмента миграции быстро устареет.Необходимо выполнить работу по переносу вашего кода.

Некоторые основные API-интерфейсы ОС похожи, но большая часть кода платформы была перемещена или изменена, поэтому поиск аналогичных замен также может быть затруднен.На самом деле стоит провести некоторые исследования и разработки, чтобы увидеть, в чем различия, не говоря уже об использовании сторонних библиотек и т. Д.

0 голосов
/ 20 сентября 2018

Ниже приведены, по крайней мере, удовлетворительные подходы:

Спасибо Фирда из Чешской Республики. Это его ответ

1) Для меня достаточно универсальной прокладки (фрагменты могут помочь)

public abstract class Shim<TImpl>
{
    internal TImpl It { get; }
    protected Shim(TImpl it) { It = it; }
}

ПРИМЕР:

public class DispatcherPriorityShim : Shim<
#if NETFULL
    DispatcherPriority
#elif NETCORE
    string
#endif
>
{
    public DispatcherPriorityShim(string it)
#if NETFULL
        : base((DispatcherPriority)Enum.Parse(typeof(DispatcherPriority), it))
#elif NETCORE
        : base(it)
#endif
    { }
}

Мой* sdk-style .csproj файл, чтобы прояснить NETFULL и NETCORE:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup><TargetFrameworks>netstandard2.0;netcoreapp2.0;net461</TargetFrameworks></PropertyGroup>

  <PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' OR '$(TargetFramework)' == 'netstandard2.0'">
    <DefineConstants>NETCORE;</DefineConstants></PropertyGroup>

  <PropertyGroup Condition=" '$(TargetFramework)' == 'net461'">
    <DefineConstants>NETFULL;</DefineConstants></PropertyGroup>
</Project>

1.a) Visual Studio фрагменты

дрв

#if NETFULL

#elif NETCORE

#endif

шименум

namespace PortabilityLibrary.Shims
{
  public class $enumname$Shim : Shim<
#if NETFULL
    $enumname$
#elif NETCORE
    string
#endif
>
  {
        public $enumname$Shim(string it)
#if NETFULL
        : base(($enumname$)Enum.Parse(typeof($enumname$), it))
#elif NETCORE
          : base(it)
#endif
        { }
  }
}

шимснип

namespace PortabilityLibrary.Shims
{
  public class $classname$Shim : Shim<
#if NETFULL
    $classname$
#elif NETCORE
    $classname$
//NullObject
#endif
>
  {
        public $classname$Shim()
#if NETFULL
        : base(new $classname$())
#elif NETCORE
        : base(new $classname$())
    //: base(new NullObject())
#endif
        {}
  }
}

шиммет

        public void $methodname$()
        {
#if NETFULL
        It.$methodname$();
#elif NETCORE
        It.$methodname$();
        //throw new ShimException();
#endif
        }

shimprop - еще нет


2) Случай, когда необходимо наследование.

public interface IShimOne
{
    void MethodOne();
}
public interface IShimTwo: IShimOne
{
    void MethodTwo();
}
#if NETFULL
class One: RealOne, IShimOne {}
class Two: RealTwo, IShimTwo {}
public static class ShimFactory
{
    public static IShimOne CreateOne() { return new One(); }
    public static IShimTwo CreateTwo() { return new Two(); }
}

2.a)Объекты для наследования

public class WrapperOne
{
    protected IShimOne It { get; }
    protected WrapperOne(IShimOne it) { It = it; }
    public WrapperOne() { It = ShimFactory.CreateOne(); }
    public void MethodOne() { It.MethodOne(); }
}
public class WrapperTwo: WrapperOne
{
    protected new IShimTwo It => (IShimTwo)base.It;
    protected WrapperTwo(IShimTwo it): base(it) {}
    public WrapperTwo(): base(ShimFactory.CreateTwo()) {}
    public void MethodTwo() { It.MethodTwo(); }

3) Готовые «аналоги» для элементов управления графическим интерфейсом ( Eto.Forms )

(собственно, Eto.Forms имеет более широкое применение- это прокладки)

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

//Not fully implemented, just showing the idea:

#if NETFULL
using System.Windows.Controls;
#elif NETCORE
using Eto.Forms;
#endif

namespace PortabilityLibrary.Shims
{
    public class MenuItemShim : Shim<
#if NETFULL
    MenuItem
#elif NETCORE
    MenuItem
#endif
    >
    {
        public MenuItemShim(EventHandler<EventArgs> dlg)
#if NETFULL
        : base(new MenuItem(/*not implemented*/))
#elif NETCORE
        : base(new ButtonMenuItem(dlg))
#endif
        { }
    }
}
...