webentwicklung-frage-antwort-db.com.de

Wie können fertige Shims für die Portierung von .NET Framework auf .NET Core/Standard erstellt oder verwendet werden?

Wie kann man fertig Shims für .net framework 4.6.1-Elemente erstellen oder verwenden, um sie zu portieren (von .net framework 4.6.1) nach .net core 2.0/.net standard 2.0?


Einige Interessenkategorien:, es wäre schön, Unterlegscheiben für folgende Klassen zu haben:

System.Windows.Threading.Dispatcher

oder 

System.ComponentModel.ItemPropertyInfo.Descriptor

sogar

System.Windows.Controls.MenuItem

und viele mehr... 


Kontext:

Die Anwendung (der Code) ist nicht zu 100% gut organisiert. Die Geschäftslogik ist nicht zu 100% von der Benutzeroberflächenlogik getrennt. Die Antwort "do refactoring first" ist definitiv eine gute Antwort. Aber in meinem Fall sind die Dinge nicht zu 100% so, wie sie ideal sein sollten.


Ungefähres Beispiel, ein Versuch, es manuell auszuführen: 

System.Windows.Threading.Dispatcher ist in Core 2.0 nicht implementiert.

Man könnte versuchen, Folgendes hinzuzufügen:

public enum DispatcherShimPriority
{
    Background
    //...
}

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

Es folgen zwei Implementierungen dieser Schnittstelle:

public class DispatcherCore: DispaicherShim;

und

public class DispatcherFramework: DispaicherShim;

Gefolgt von einer Klasse (nennen wir sie Shims) in einem Projekt mit mehreren Zielen:

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

Das Ergebnis ist das Shim, das in verschiedenen APIs verwendet werden kann.

Ist das ein korrekter Ansatz?


Tatsächlich erfordert das Erstellen solcher Unterlegscheiben viel Routinearbeit. Ich habe das Gefühl, dass diese Arbeit nicht notwendig ist. Ich habe das Gefühl, dass es eine bereite Lösung für dieses Problem gibt ...


Mir ist das Microsoft.Windows.Compatibility-Paket bekannt. Die Frage bezieht sich eher auf die Portierung, wenn WPF mit vielen wpf-spezifischen Elementen verbunden ist. Diese Elemente befinden sich nicht im Microsoft.Windows.Compatibility-Paket, werden jedoch leider in allen Assemblys verwendet, die Kandidaten für das Retargeting auf .Net Core 2.0 sind. Ich meine die Klassen, die nicht in Microsoft.Windows.Compatibility sind. 

Ok, wir haben diesen Microsoft.Windows.Compatibility.Shims, aber ich bin nicht sicher, ob es in meinem Fall nützlich ist. besonders nach dem Lesen des folgenden Textes :

Microsoft.Windows.Compatibility.Shims: Dieses Paket enthält Infrastrukturdienste und sollte nicht direkt von .__ referenziert werden. dein Code....


Upd: und hebt hervor, dass das Endziel .net core 2.0 ist.

Upd2: Die gesamte Aufgabe besteht darin, den Hauptteil einer WPFApp zu .net core (die funktionierende WPFApp) für potentielle Web- Klient. Der Hauptteil enthält .net framework-Elemente, die nicht für .net core implementiert sind.

Upd3: Ein paar Worte zur vollständigen Strategie: Die umfassendere Strategie ist Gemeinsame Projekte, erster Ansatz in diesem Artikel (#if) . Es gibt zwei Hauptschritte in meiner Strategie: Erstens, den Code schrittweise zu portieren, angefangen von Basisbibliotheken bis hin zu Spitzenbibliotheken, aber mit intensiver Verwendung von Stubs und PlatformNotSupportedExceptions. Der zweite Schritt besteht darin, von Top-Bibliotheken zu Basisbibliotheken zu wechseln, bei denen Stubs und Ausnahmen durch .net-Kernimplementierungen ersetzt werden. Bei Bedarf (!) Müssen keine Stubs und Ausnahmen ersetzt werden.

Upd4 Wir haben bereits portable Tests von nicht portablen Tests (in zwei Bibliotheken) aufgeteilt. Es ist sehr wichtig, dass wir die Tests während des Portierungsprozesses ausführen.

18
Andrey K.

Der Wechsel von Standard .Net zu .Net Core ist nicht nur ein Upgrade, man könnte fast von einer neuen Plattform sprechen, wenn man bedenkt, wie alles zusammengefügt wird. Der Wechsel zu .Net Core bedeutet, ein neues Framework zu erlernen und zu erstellen, in das vorhandener Code kopiert werden kann.

Aufgrund der großen Unterschiede zwischen .Net Core 1, 1.1, 2.0 und 2.1 hat sich der Migrationsprozess stark verändert, so dass es keine 1-Größe für alle "Shim" gibt und ein Wrapper oder ein Migrationstool schnell erstellt werden müsste obsolet. Es muss gearbeitet werden, um Ihren Code zu migrieren.

Einige Kern-APIs für Betriebssysteme sind ähnlich, es wurde jedoch ein großer Teil des Framework-Codes verschoben oder geändert. Daher kann es auch schwierig sein, nach ähnlichen Swaps zu suchen. Es lohnt sich wirklich, einige Forschungs- und Entwicklungsarbeiten durchzuführen, um zu sehen, wo die Unterschiede nicht zu erwähnen sind, nicht die Verwendung von Bibliotheken von Drittanbietern usw.

4
Mark Redman

Im Folgenden sind zumindest zufriedenstellende Ansätze:

Danke Firda aus Tschechien. Das ist seine Antwort

1) Generisches Shim ist genug für mich (Schnipsel können helfen)

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

BEISPIEL:

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

Meine sdk-style .csproj-Datei zum Verdeutlichen von NETFULL und 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 Schnipsel

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 - noch nicht


2) Fall, wenn Vererbung erforderlich ist.

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) Objekte zur Vererbung

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) Fertige "Gegenstücke" für GUI-Steuerelemente ( Eto.Forms )

(eigentlich hat Eto.Forms eine breitere Anwendung - sie sind die Unterlegscheiben)

Dieses Framework kann zum Erstellen von Anwendungen verwendet werden, die über mehrere Plattformen mit ihrem nativen Toolkit mit einer benutzerfreundlichen API ausgeführt werden. Dadurch werden Ihre Anwendungen als native Anwendung auf allen Plattformen mit einer einzigen UI-Codebasis aussehen und funktionieren ...

//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.