简体   繁体   中英

How to implement Factory Interface in Simple Injector With Parameters

This answer shows how to resolve instances using a factory interfaces without parameters.

I am using the following code

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>();
    }
}

to resolve instances which have constructor parameters.

However, I get the following exception when using the factory to instantiate the service class:

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

Which is the right way of to resolve instances using factory interfaces with parameters?

Update

The following is my code. I am migrating the code from 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 class to be injected

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

 }

Instantiating code:

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

var frm = _uiFactory.CreateAccountUI(account);

The problem you are having is caused by the fact that you are mixing runtime data (your Account ) object, with components. You DI container is in charge of building object graphs of components. Those components should typically be stateless and runtime data should flow through the object graphs using method calls. Injecting runtime data in constructors of your components, makes those components statefull and complicates your application in many different ways; you are witnessing one of those complications today. But there are many of downsides of doing this. For instance, injecting runtime data into the constructor makes it impossible to verify your object graph (using an automated test) and makes it easy for your application to break at runtime. So this in no way Simple Injector specific, but Simple does make the problem more eminent by not allowing to passing in runtime values when resolving services. You can find a detailed explanation about this here .

So instead, try to keep your components as stateless as possible and at least keep runtime data out of the constructor. A simple way to achieve this is to add a property to the form that allows setting the entity you are working with. A generic interface can be added to a form to allow this:

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

This generic interface can be used in the IFormFactory abstraction:

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

Creating an implementation for IFormFactory is as easy as this:

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;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM