• 将Asp.Net Core和corefx移植到.Net 4.0


    引言

    因为工作内容的原因需要兼容 XP,而 XP 最多支持到.Net Framework 4.0。因此无法享受到 .Net Core 带来的一堆很好用的库,好在无论 corefx 还是 Asp.Net Core 都是开源的,我们可以自行修改编译出支持 .Net 4.0 的版本。

    技术可行性

    Net 4.0 相比 4.5 和 netstandard 1.0,主要的差别有:

    • System.Threading.Tasks.Task 类型。.Net 4.0 的 Task 没有 GetAwaiter 成员,编译器无法生成使用 async await 的代码。好在编译器查找 Task.GetAwaiter 并不是直接查找成员方法,如果是扩展方法也可以,那么我们通过对 Task 编写 GetAwaiter 扩展方法就可以在 .Net 4.0 中使用 async await 了。
    • Reflection 类别的 API。.Net 4.5 对反射 API 进行了重构,分离出了 TypeInfo 用于运行时反射。在 .Net 4.0 中,我们可以自行编写一个 TypeInfo 类,但是 .Net 4.5 中 TypeInfo 继承自 Type。据我观察实现中 GetType 返回的对象实际上就是一个 TypeInfo 对象,这一点我们无法通过自己编写的 TypeInfo 做到,不过好在除了 mscorlib,其他库并没有用到这层继承关系,因此为了不产生问题我实现的 TypeInfo 没有继承自 Type。
    • WeakReference<T>。.Net 4.5 中的 WeakReference<T> 并没有继承自 WeakReference,它的终结器方法是一个 InternalCall,也就是在 clr 中实现的。而我们无法修改 clr 的实现,因此我实现的 WeakReference<T> 继承自 WeakReference,重用了它的终结器。
    • 其它一些类型中 API 的缺失。主要包括 GC、Cryptography。对于没有的类型,我们可以添加实现,但对于已存在的类型是没有办法进行修改的。虽然 clr 中有 TypeForwardTo,配合 assembly redirecting 技术可以替换类型的实现,但 .Net 4.0 编译的程序集默认引用了 mscorlib,而 mscorlib 并不能被 redirect,所以对于 mscorlib 中已存在类型的 API 缺失——这一点暂时没有办法解决。

    已经移植的项目

    corefx

    • System.Runtime:添加了 ExceptionDispatchInfo、IReadOnlyCollection<T>等一些只读集合的接口、生成异步方法所需要的 AsyncStateMachineAttribute、以及使用 MVVM 中很常用的 CallerMemberNameAttribute 等
    • System.AppContext:添加了 AppContext 类
    • System.Runtime.CompilerServices.Unsafe:添加了 Unsafe 类(ref 和 指针转换、直接读写内存等)
    • System.Threading:添加了 Volatile 类
    • System.Threading.Tasks:添加支持 async await 相关的类
    • System.Security.Cryptography.Algorithms:添加了 IncrementalHash 的实现

    Asp.Net Core

    • Microsoft.Extensions.DependencyInjection
    • Microsoft.Extensions.Options
    • Microsoft.Extensions.Configuration

    这些写过 Asp,Net Core 的应该很熟悉,他们也可以用在普通的 .Net 桌面程序中

    一些开源项目

    • Autofac:一个功能很强大的 IoC 实现
    • AutoMapper:对象间的映射
    • MaterialDesignThemes:WPF 的 MaterialDesign

    示例

    • 新建一个 .Net 4.0 项目
    • 在 Nuget 程序包源里加上 https://www.myget.org/F/dotnet40/api/v3/index.json,并将优先级调到最上面
    • install-package System.Threading.Tasks -Version 4.3.0-net40(注意一定要加上 Version)
    • 在 app.config 加上 assembly redirecting
          <dependentAssembly>
            <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Threading" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-4.0.12.0" newVersion="4.0.12.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-4.0.12.0" newVersion="4.0.12.0" />
          </dependentAssembly>
    
    •  然后你就可以愉快的 async await 了

    下面的示例是使用了

    Caliburn.Micro

    Microsoft.Extensions.DependencyInjection

    Microsoft.Extensions.Configuration

    Autofac

    Autofac.Extensions.DependencyInjection

    AutoMapper

    AutoMapper.Extensions.Microsoft.DependencyInjection

        public class AppBootstrapper : BootstrapperBase
        {
            public IConfiguration Configuration { get; }
            public IServiceProvider ServiceProvider { get; private set; }
            private IContainer _container;
    
            public AppBootstrapper()
            {
                Configuration = LoadConfiguration();
                Initialize();
            }
    
            private IConfiguration LoadConfiguration()
            {
                var builder = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("config.json", false, false);
                return builder.Build();
            }
    
            protected override void Configure()
            {
                var serviceCollection = new ServiceCollection();
                ServiceProvider = ConfigureServices(serviceCollection);
            }
    
            public IServiceProvider ConfigureServices(IServiceCollection services)
            {
                services.AddOptions();
                services.AddAutoMapper(AssemblySource.Instance.ToArray());
                services.AddSingleton<IWindowManager>(new WindowManager());
                services.AddSingleton<IEventAggregator>(new EventAggregator());
                
                services.AddSingleton(p => _container);
    
                var builder = new ContainerBuilder();
                builder.Populate(services);
                builder.RegisterAssemblyModules(AssemblySource.Instance.ToArray());
    
                _container = builder.Build();
                return new AutofacServiceProvider(_container);
            }
    }
    

     看起来和在 Asp.Net Core 中没什么差别。

    总结

    虽然工作环境限制我们只能使用 .Net 4.0,但俗话说没有条件,创造条件也要上。将它们移植到 .Net 4.0 也是跟上 .Net Core 和开源的步伐的一种努力吧。

    关于这些包和相关的版本号可以在 https://www.myget.org/feed/Packages/dotnet40 查看

    关于移植到 .Net 4.0 的计划我创建了一个 github 组织,里面包含移植的所有项目 https://github.com/dotnet40/

    最后,感谢大家花时间阅读!

  • 相关阅读:
    qt获取本机ip
    qt获取本机用户名
    QT获取主机名称
    关于代码控制管理的一些想法
    QLabel添加Click信号
    QT中,控件显示不下,用...表示
    qt获取屏幕
    Matlab boxplot for Multiple Groups(多组数据的箱线图)
    Linux Bash代码 利用for循环实现命令的多次执行
    DataProcessing
  • 原文地址:https://www.cnblogs.com/sunnycase/p/7239507.html
Copyright © 2020-2023  润新知