如何在带参数的简单注入器中实现工厂接口

时间:2015-07-20 13:06:35

标签: c# dependency-injection simple-injector

This answer显示了如何使用不带参数的工厂接口来解析实例。

我正在使用以下代码

public interface ISimpleBarFactory 
{
   Bar CreateBar(int value);
}

public sealed class SimpleBarFactory : ISimpleBarFactory 
{
    private readonly Container _container;
    public SimpleBarFactory (Container container)
    {
        _container = container;
    }

    public Bar CreateBar(int value) 
    {
       _container.Register(() => new Bar(vlue));
       return _container.GetInstance<Bar>();
    }
}

解析具有构造函数参数的实例。

但是,在使用工厂实例化服务类时,我得到以下异常:

The container can't be changed after the first call to GetInstance, GetAllInstances and Verify.

使用带参数的工厂接口解析实例的正确方法是什么?

更新

以下是我的代码。我正在从Ninject迁移代码。

public interface IFormsUIFactory
{
   AccountUI CreateAccountUI(Account account);
}

public class FormsUIFactory
{
    private readonly IFormsUIFactory _uiFactory;
    public FormsUIFactory(IFormsUIFactory uiFactory)
    {
        _uiFactory = uiFactory;
    }

    public void CreateAccountUI(Account account)
    {
        _uiFactory.CreateAccountUI(account);
    }
}

要注入的UI类

public partial class AccountUI : Form
{
    private readonly IAccountMaintenanceProcessor _processor;
    private readonly Account _account;
    public AccountUI(IAccountMaintenanceProcessor accountProcessor, Account account)
    {      
        _processor = accountProcessor;
        _account = account;
    }

 }

实例化代码:

var account = new Account();
// Populate values for the account

var frm = _uiFactory.CreateAccountUI(account);

1 个答案:

答案 0 :(得分:1)

您遇到的问题是由于您正在将运行时数据(您的Account)对象与组件混合在一起。你DI容器负责构建组件的对象图。这些组件通常应该是无状态的,运行时数据应该使用方法调用流过对象图。在组件的构造函数中注入运行时数据,使这些组件成为有状态的,并以多种不同的方式使应用程序复杂化;你正在目睹今天的复杂情况之一。但这样做有许多缺点。例如,将运行时数据注入构造函数使得无法验证对象图(使用自动化测试),并使应用程序在运行时更容易中断。所以这绝不是Simple Injector特有的,但Simple通过不允许在解析服务时传递运行时值来使问题更加突出。 您可以找到有关此here的详细说明。

因此,请尽量保持组件尽可能无状态,并至少将运行时数据保留在构造函数之外。实现此目的的一种简单方法是向表单添加属性,以允许设置您正在使用的实体。可以将通用接口添加到表单中以允许此操作:

interface IForm<TEntity>
{
    TEntity Entity { get; set; }
}

此通用接口可用于IFormFactory抽象:

interface IFormFactory
{
    TForm CreateFormFor<TForm, TEntity>(TEntity entity) 
        where TForm : Form, IForm<TEntity>;
}

IFormFactory创建实现就像这样简单:

public class FormFactory : IFormFactory
{
    private readonly Container container;

    public FormFactory(Container container) {
        this.container = container;
    }

    public TForm CreateFormFor<TForm, TEntity>(TEntity entity) 
        where TForm : Form, IForm<TEntity> {
        var form = this.container.GetInstance<TForm>();
        form.Entity = entity;
        return form;
    }
}