【问题标题】:How to use DI in WPF to having a new istance without ask to container如何在 WPF 中使用 DI 来拥有一个新实例而不询问容器
【发布时间】:2020-09-11 12:46:17
【问题描述】:

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

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

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

正如@Steven 在我之前的帖子中所说的那样

请注意,瞬态意味着“总是在从容器请求时解析新实例”。如果您不再请求它,您将在同一个实例上操作,这可能会解释 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 的工作原理而制作的一个示例。

【问题讨论】:

  • 你能举一个小代码例子吗? 3 行代码相当于 1000 字。
  • 您如何解决需要 unitOfWork 的服务?
  • 我已经发布了所有代码in my previous post,但现在我通过添加部分代码进行编辑。
  • @mm8 服务被构造函数注入解析

标签: c# wpf inversion-of-control simple-injector


【解决方案1】:

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

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

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

我对 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");
}

【讨论】:

  • Thk @BionicCode,这类似于我在my other post 中尝试对第二个版本进行的操作,但这是一个非常干净的示例。我会尽量这样做
猜你喜欢
  • 2016-08-26
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
  • 2017-03-13
  • 1970-01-01
  • 2020-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多