如何在 WPF 中使用 DI 来拥有一个新实例而不询问容器

How to use DI in WPF to having a new istance without ask to container

我正在尝试使用 Simpleinjector 作为 IOC 容器从头开发 WPF 应用程序。 我是这个话题的新手,我有一些关于对象生命周期和正确热使用它们的问题。

我按照 simpleinjector 手册上的 WPF 集成指南启动了该应用程序。 但是我不明白每次服务需要时如何接收新实例

As i ask in my previous post 每次服务需要时,我都需要接收一个新的 unitOfWork。

正如@Steven 在我之前所说的 post

Do note that transient means "allways a new instance is resolved when it is requested from the container." If you're not requesting it again, you will be operating on the same instance, which might explain the ObjectDisposedException.

the other post 中,我找到了一个解决方案,但我认为它有点过于复杂,它是创建一个工厂并注入它而不是实例,因为我只想调用 container.getInstance通过将容器作为依赖项传递给启动方法而不是服务

这是我必须实现此目标的唯一方法,或者我不了解如何以 DI 方式开发?

代码示例:

public class HeaderViewModelFactory : IWpfRadDispenserViewModelFactory<HeaderviewModel>
{
    private readonly ProductionService _service;

    public HeaderViewModelFactory(ProductionService service)
    {
        _service = service;
    }

    public HeaderviewModel CreateViewModel()
    {
        return new HeaderviewModel(_service);
    }
}

public class HeaderviewModel : ViewModelBase
{
    private readonly ProductionService _service;
    
    public HeaderviewModel(ProductionService service)
    {
        _service = service;
        CreateData();
    }

    private void CreateData()
    {
        _service.CreateTestCycle();
    }
}


public class CycleService : GenericDataService<Cycle>
{
    private readonly IUnitOfWork<WpfRadDispenserDbContext> _uowContext;
    
    public CycleService(IUnitOfWork<WpfRadDispenserDbContext> uowContext)
        : base(uowContext)
    {
        _uowContext = uowContext;
    }

    public void CreateTestCycle()
    {
        var cycleDataService = new GenericDataService<Cycle>(_uowContext);
        var vialDataService = new GenericDataService<Vial>(_uowContext);

        Cycle c = new Cycle();
        c.BatchName = "test";

        Vial v = new Vial();
        v.Name = "Test Vial";
        c.Vials.Add(v);

        _uowContext.CreateTransaction(IsolationLevel.ReadCommitted);
        try
        {
            vialDataService.Create(v);
            _uowContext.Persist();

            var list = vialDataService.GetAll();

            cycleDataService.Create(c);
            _uowContext.Persist();
            _uowContext.Commit();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            _uowContext.RollBack();
            throw;
        }
        finally
        {
            _uowContext.Dispose();
        }
    }
}

private static Container Bootstrap()
{
    // Create the container as usual.
    var container = new Container();
    // Register your types:
    // Register your windows and view models:

    container.Register<WpfRadDispenserDbContextFactory>(Lifestyle.Transient);
    container.Register<IUnitOfWork<WpfRadDispenserDbContext>,WpfRadDispenserUOW>();
    container.Register(typeof(CycleService));

    container.Register<IWpfRadDispenserViewModelFactory<ProductionViewModel>,
                            ProductionViewModelFactory>(Lifestyle.Transient);
    container.Register<IWpfRadDispenserViewModelFactory<AnagraphicViewModel>, 
                            AnagraphicsViewModelFactory>(Lifestyle.Transient);

    container.Register<IWpfRadDispenserViewModelFactory<HeaderviewModel>,
        HeaderViewModelFactory>(Lifestyle.Transient);

    container.Register<IViewModelAbstractFactory,
        ViewModelAbstractFactory>(Lifestyle.Transient);

    container.Register<INavigator, Navigator>(Lifestyle.Transient);
    container.Register<MainWindowViewModel>();
    container.Register<MainWindow>();

    //container.Options.EnableAutoVerification = false;
    //container.Verify();
    return container;
}

以这种方式,每次我创建一个新的视图模型时,我都会收到相同的服务,而且很明显,dbcontext 不再存在,因为已处理。

这不是 rela 代码,只是我为了理解 DI 的工作原理而做的一个例子。

使用抽象工厂模式是最常见和推荐的方法。直接在应用程序中使用容器被广泛认为是 anti-pattern,就像服务定位器 (Service Locator is an Anti-Pattern) 一样,这是有充分理由的。

抽象工厂允许实例化对象,而无需引入与知道如何创建特定实例的实际实现的紧密耦合。

大多数 IoC 框架本身就支持这种模式。大多数时候,它们为工厂提供通用接口。您向容器注册实例(产品),框架将为您导出一个 ready-to 使用工厂。您将此框架接口的依赖项添加到您的对象,例如构造函数。然后注册通用工厂接口。该框架将自动创建工厂实例并将其注入相关实例,例如通过构造函数。

我对Simple Injector不是很熟悉,但是这个框架确实让事情变得简单了。没有这样的代码生成。
但是模式非常简单(这就是为什么它很容易自动化)而且一点也不复杂。

例子

动态创建类型实例所需的接口TInstance:

interface IFactory<TInstance>
{
  TInstance Create();
}

这个工厂的实现:

class SaveItemFactory : IFactory<ISaveItem>
{
  ISaveItem Create() => new SaveItem();
}

需要动态创建依赖的类型:

interface IItemManager {}

class ItemManager : IItemManager 
{
  IFactory<ISaveItem> SaveItemFactory { get; }

  public ItemManager(IFactory<ISaveItem> itemFactory) => this.SaveItemFactory = itemFactory;

  public void SaveData(object data)
  {
    ISaveItem saveItem = this.SaveItemFactory.Create();
    saveItem.SetData(data);
  }
}

配置容器:

public void Run()
{
  var container = new SimpleInjector.Container();

  container.Register<IFactory<ISaveItem>, SaveItemFactory>(Lifestyle.Singleton);
  container.Register<IItemManager, ItemManager>(Lifestyle.Singleton);

  IItemManager itemManager = container.GetInstance<IItemManager>();
  itemManager.SaveData("Some Data");
}