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 PlatformNotSupportedException
s. 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.
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.
Im Folgenden sind zumindest zufriedenstellende Ansätze:
Danke Firda aus Tschechien. Das ist seine Antwort
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>
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
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(); }
}
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(); }
(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
{ }
}
}