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);
答案 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;
}
}