Avaonia11中如何优雅的使用DI

172 阅读2分钟

背景

项目开发到现在,越来越多的ViewModel对象,需要对象便New,传递对象通过构造函数或属性,使得代码的耦合性越来越大。

想到能否有一个容器统一的管理对象???

需要的时候就直接从容器中取就行,切容器的对象是自动管理依赖关系的,就像Java语言中的SpringIOC一样。

发现Microsoft.Extensions.DependencyInjection正好解决了这个问题,于是便有了下文。

使用方法:

添加Microsoft.Extensions.DependencyInjection到项目中,使用NuGet管理器或者命令行;

关键代码:

  1. 添加服务管理类,用于全局管理对象示例:
using Microsoft.Extensions.DependencyInjection;
using System;

namespace abc.Services;

public static class ServiceLocator
{
    private static IServiceProvider _serviceProvider;

    public static void Initialize(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public static T GetService<T>() where T : class
    {
        return _serviceProvider.GetService<T>();
    }
}

  1. 添加对象注入到容器中;
private IServiceProvider? _provider;
public override void Initialize()
{
    AvaloniaXamlLoader.Load(this);
    _provider = ConfigureServices();
    // 初始化服务定位器
    ServiceLocator.Initialize(_provider);
}
public override void OnFrameworkInitializationCompleted()
{
    var viewLocator = _provider?.GetRequiredService<IDataTemplate>();
    var mainViewModel = _provider?.GetRequiredService<MainViewModel>();
    var mainWindow = _provider?.GetRequiredService<MainWindow>();

    if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
    {
        desktop.MainWindow = mainWindow;
    }
    else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)

    {
        singleViewPlatform.MainView = new MainView1
        {
            DataContext = mainViewModel
        };
    }
    base.OnFrameworkInitializationCompleted();
}

private static ServiceProvider ConfigureServices()
{
    var viewLocator = Current?.DataTemplates.First(x => x is ViewLocator);
    var services = new ServiceCollection();
    // Views
    services.AddSingleton<MainWindow>();

    // Services
    if (viewLocator is not null)
        services.AddSingleton(viewLocator);

    // ViewModels
    var types = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(s => s.GetTypes())
        .Where(p => !p.IsAbstract && typeof(ViewModelBase).IsAssignableFrom(p));
    foreach (var type in types)
    {
        services.AddSingleton(type);
    }
    return services.BuildServiceProvider();
}

public class OneViewModel : ViewModelBase{}
public class TwoViewModel : ViewModelBase{}
public class ThreeViewModel : ViewModelBase{}
...

前后代码对比:

可见,对比结果一目了然,不仅代码简洁了而且还解耦了。

深潜:

  1. 除了通过构造函数的方式注入,是否能通过注解的方式注入对象呢?比如像Spring中的@AutoWired?
  2. 在使用的过程中发现AvaloniaEdit.Utils包下同样包含ServiceCollection,那是否Avalonia11本来就包含对象管理容器而不需要引入三方的轮子呢?
  3. 使用时注意循环嵌套问题,如果程序一直加载不完最终内存溢出,那多半就是循环依赖了,检查对象依赖关系,不能A->B->C->A这样。

总结:

  1. 介绍了Microsoft DI的使用方法,当然同类的轮子还有好多,选择微软,是因为开发语言和使用的.Net Core都是一家;
  2. 添加的服务管理类ServiceLocator使得在其他对象中使用另外对象变的很方便,同时也降低了New对象造成的耦合性;

本文完。