web-dev-qa-db-fra.com

Comment créer ou utiliser des shims prêts pour le transfert de .net framework vers .net core/standard

Comment créer ou utiliser les éléments ready Shims for .net framework 4.6.1 pour les porter (de .net framework 4.6.1) à .net core 2.0.net standard 2.0?


_/Quelques classes d’intérêt:, il serait bien d’avoir des cales pour des classes comme:

System.Windows.Threading.Dispatcher

ou 

System.ComponentModel.ItemPropertyInfo.Descriptor

même

System.Windows.Controls.MenuItem

et beaucoup plus... 


Le contexte:

L'application (le code) n'est pas bien organisée à 100%. La logique métier n'est pas séparée à 100% de la logique de l'interface utilisateur. La réponse "refactoriser d'abord" est certainement une bonne réponse. Mais dans mon cas, les choses ne sont pas à 100% comme elles devraient idéalement être.


Exemple approximatif, essayez de le faire manuellement: 

System.Windows.Threading.Dispatcher n'est pas implémenté dans Core 2.0.

On pourrait essayer d'ajouter:

public enum DispatcherShimPriority
{
    Background
    //...
}

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

Suivie de deux implémentations de cette interface:

public class DispatcherCore: DispaicherShim;

et

public class DispatcherFramework: DispaicherShim;

Suivi par une classe (appelons-la Shims) dans un projet à cibles multiples:

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

Le résultat est la cale, qui pourrait être utilisée dans différentes API.

Est-ce une approche correcte?


En réalité, créer de telles cales nécessite beaucoup de travail de routine. J'ai le sentiment que ce travail n'est pas nécessaire pour être effectué. J'ai le sentiment qu'il existe une solution prête pour ce problème ...


Je connais le paquet Microsoft.Windows.Compatibility. La question est plutôt liée au portage lorsque WPF est impliqué dans de nombreux éléments spécifiques à wpf. Ces éléments ne sont pas dans le package Microsoft.Windows.Compatibility, mais, malheureusement, ils sont utilisés dans l'ensemble de mes assemblys, candidats au reciblage vers .Net Core 2.0. Je veux dire ajuster ces classes, qui ne sont pas dans Microsoft.Windows.Compatibility

Ok, nous avons ce Microsoft.Windows.Compatibility.Shims, mais je ne suis pas sûr que cela soit utile dans mon cas; surtout après avoir lu le texte suivant :

Microsoft.Windows.Compatibility.Shims: ce paquet fournit services d’infrastructure et ne doit pas être référencé directement à partir de votre code....


Upd: soulignant que la cible finale est .net core 2.0

Upd2: toute la tâche consiste à porter la majeure partie d'une application WPF vers .net core (en laissant WPF app) pour le potentiel client Web. La partie majeure contient des éléments .net framework qui ne sont pas implémentés pour .net core.

Upd3: Quelques mots sur la stratégie complète: La stratégie la plus complète est Projets partagés, première approche de cet article (#if) . Ma stratégie comporte deux étapes principales: la première consiste à porter progressivement le code, en partant des bibliothèques de base et en terminant dans les bibliothèques supérieures, mais avec un usage intensif des stubs et des PlatformNotSupportedExceptions. La deuxième étape consiste à passer des bibliothèques principales aux bibliothèques de base en substituant les stubs et les exceptions par des implémentations .net principales, à la demande (!) - inutile de remplacer tous les stubs et les exceptions.

Upd4 Nous avons déjà divisé les tests portables des tests non portables (en deux bibliothèques). Il est très important que nous exécutions les tests pendant le processus de portage.

18
Andrey K.

Passer de .Net standard à .Net Core n’est pas simplement une mise à niveau, on pourrait presque parler de migration vers une nouvelle plate-forme, en tenant compte de la façon dont les choses sont organisées. Passer au noyau .Net signifie apprendre et créer un nouveau cadre où le code existant peut être copié.

En raison des grandes différences entre .Net Core 1, 1.1, 2.0 et 2.1. Le processus de migration a beaucoup changé, il n'y a donc pas de taille unique, et il serait rapide de créer un type d'outil d'emballage ou de migration obsolète. Il vous reste du travail à faire pour migrer votre code.

Certaines API de système d'exploitation de base sont similaires, mais de nombreux codes d'infrastructure ont été déplacés ou modifiés. Il peut donc s'avérer difficile de procéder de la même manière. Cela vaut vraiment la peine de faire de la R & D pour voir où les différences ne sont pas à mentionner l'utilisation de bibliothèques tierces, etc.

4
Mark Redman

Voici des approches au moins satisfaisantes:

Merci Firda de République tchèque. C'est sa réponse

1) Une cale générique me suffit (des extraits peuvent aider)

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

EXEMPLE:

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
    { }
}

Mon fichier .csproj de style sdk pour préciser les NETFULL et 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 extraits

drv

#if NETFULL

#Elif NETCORE

#endif

shimenum

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
        { }
  }
}

shimsnip

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
        {}
  }
}

shimmeth

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

shimprop - pas encore


2) Cas où l'héritage est nécessaire.

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) Objets pour héritage

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) "homologues" prêts pour les commandes de l'interface graphique ( Eto.Forms )

(En fait, Eto.Forms a une application plus large - ce sont les cales)

Cette infrastructure peut être utilisée pour créer des applications qui s'exécutent sur plusieurs plates-formes à l'aide de leur boîte à outils native, avec une API facile à utiliser. Cela donnera à vos applications une apparence et un fonctionnement natifs sur toutes les plates-formes, en utilisant une seule base de code d'interface utilisateur ...

//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
        { }
    }
}
0
Andrey K.