C# 如何创建或使用现成的垫片从.net framework移植到.net core/standard?
如何为C# 如何创建或使用现成的垫片从.net framework移植到.net core/standard?,c#,.net,.net-core,porting,shim,C#,.net,.net Core,Porting,Shim,如何为.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 还有更多
.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%组织良好。业务逻辑与UI逻辑并非100%分离。答案“首先进行重构”绝对是一个好答案。但在我的情况下,事情并不是100%的理想状态
近似示例,一个尝试按常规操作的示例:
System.Windows.Threading.Dispatcher
未在核心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;
及
在多目标项目中,后跟一个a类(我们称之为a
):
public static DispaicherShim CreateDispatcher()
{
#if NETCOREAPP2_0
return new DispatcherCore();
#else
return new DispatcherFramework();
#endif
}
结果就是垫片,可以在不同的API中使用
这是正确的方法吗?
实际上,制作这样的垫片需要很多日常工作。我觉得这项工作没有必要进行。我觉得这个问题有现成的解决办法
我知道
Microsoft.Windows.Compatibility
package。当WPF
涉及许多特定于WPF的元素时,问题与移植相关。这些元素不在Microsoft.Windows.Compatibility包中,但不幸的是,它们在我的程序集中使用,这些程序集是重定目标到.Net Core 2.0
的候选程序集。我的意思是填充那些不在Microsoft.Windows.Compatibility
中的类
好的,我们有这个Microsoft.Windows.Compatibility.垫片
,但我不确定它对我的情况是否有用;特别是在阅读了以下内容后:
Microsoft.Windows.Compatibility.垫片:此软件包提供
基础设施服务,不应直接从
你的代码
Upd:强调最终目标是
.net core 2.0
Upd2:整个任务是将WPF应用程序的主要部分移植到.net core
(离开工作的WPF应用程序)以供潜在的web客户端使用。主要部分包含.net framework
元素,这些元素不是为.net core
实现的
Upd3:关于完整战略的两个词:越完整的战略是共享项目。在我的策略中有两个主要步骤:一个是逐渐移植代码,从基本库开始,在顶级库结束,但大量使用存根和PlatformNotSupportedException
s。第二步是从顶级库转移到基本库,通过.net核心实现按需替换存根和异常(!)-无需替换所有存根和异常
Upd4我们已经将可移植测试与非可移植测试分开(分成两个LIB)。在移植过程中运行测试非常重要。以下是至少令人满意的方法: 捷克共和国的感谢 1) 通用垫片对我来说已经足够了(代码片段可能会有所帮助) 1.a)Visual Studio 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
{ }
}
}
shimprop-还没有
2) 需要继承时的情况。 2.a)继承对象
3) 准备好GUI控件的“对应项”() (实际上,Eto.Forms的应用范围更广——它们是填隙片) 此框架可用于构建应用程序,这些应用程序使用其本机工具包和易于使用的API跨多个平台运行。这将使您的应用程序在所有平台上都像本机应用程序一样,使用单个UI代码库
//没有完全实现,只是展示了想法:
#如果未满
使用System.Windows.Controls;
#艾利夫网芯
使用Eto.Forms;
#恩迪夫
命名空间可移植性库
{
公共类菜单项填隙:填隙<
#如果未满
梅努伊特姆
#艾利夫网芯
梅努伊特姆
#恩迪夫
>
{
公共菜单项(EventHandler dlg)
#如果未满
:base(新菜单项(/*未实现*/))
#艾利夫网芯
:基础(新按钮菜单项(dlg))
#恩迪夫
{ }
}
}
从标准.Net移动到.Net核心不仅仅是一种升级,考虑到事物的组合方式,您几乎可以称之为移动到新平台。迁移到.NETCore意味着学习并创建一个可以复制现有代码的新框架
由于.Net core 1、1.1、2.0和2.1之间的巨大差异,这些版本的迁移过程发生了很大的变化,因此不存在“一刀切”的“垫片”,使用某种包装器或迁移工具很快就会过时。迁移代码需要做一些工作
一些核心操作系统API是类似的,但是很多框架代码已经被移动或更改,所以寻找类似的交换可能也很困难。做一些研究和开发工作确实值得,看看其中的差异在哪里,更不用说第三方库的使用等了。这是一个非常有趣的问题,但我不确定这里是否有灵丹妙药。我以前转换过应用程序,一种循序渐进的方法似乎效果最好,使用现有代码并慢慢地对其进行重新分解和升级,.NET核心库可以被.NET framework项目引用()-作为维护和部署的常规策略的一部分,我会逐渐将逻辑移到新的库文件中。在我看来,在缺乏更完整的战略的情况下,填隙片听起来有点像是在转移注意力
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
{ }
}
<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>
#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
}
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(); }
//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
{ }
}
}