Patrik Bak
Patrik Bak

Reputation: 538

NInject complex injection with dynamic data

I have an algorithm to run, like this:

public interface IAlgorithm
{
    void Run();
}

It depends on the IContainer interface that looks like this:

public interface IContainer
{
    int Size();
}

The implemention of this interface needs some data gotten from UI

public class Container : IContainer
{
    private readonly List<int> _data;

    public Container(IEnumerable<int> data)
    {
        _data = new List<int>(data);
    }

    public int Size()
    {
        return _data.Count;
    }
}

Then the implementation of IAlgorithm might look like this:

public class Algorithm : IAlgorithm
{
    private readonly IContainer _container;

    public Algorithm(IContainer container)
    {
        _container = container;
    }

    public void Run()
    {
        Console.WriteLine(_container.Size());
    }
}

I want to implement this interface so that it's injectible via NInject (so I can use it as a constructor parameter for a ViewModel).

public interface IAlgorithmFactory
{
    IAlgorithm Create(IEnumerable<int> data);
}

The problem is: I need to be able to get the right instance of IContainer from the Kernel during the Algorithm construction. In the real-world situations the dependency graph of the algorithm is quite big and there is not one thing that needs to be created from the data, but 3 and these things are further dependencies of some other things.

My solution is that all classes that needs to be created from the data have the method called Initialize. The caller must initilize these serives before using other methods. That sounds like a bad practice.

In fact, the real code that I'm talking about can be seen here. Right now everything is injected as Singleton.

Is there some other way to inject those things via NInject?

Note: I already asked this question here, from a design point of view. I think this is the better place to get the answer specifically about an NInject solution.

Upvotes: 1

Views: 393

Answers (1)

Jan Muncinsky
Jan Muncinsky

Reputation: 4408

Just by using Ninject configuration, you can do it in this way:

        var kernel = new StandardKernel();
        kernel.Bind<IContainer>()
            .To<Container>()
            .WithConstructorArgument("data",
                ctx => ctx.Request.ParentContext.Parameters
                    .Single(x => x.Name == "data")
                    .GetValue(ctx, null));
        kernel.Bind<IAlgorithm>().To<Algorithm>();
        kernel.Bind<IAlgorithmFactory>().ToFactory();

        var factory = kernel.Get<IAlgorithmFactory>();
        var algorithm = factory.Create(new List<int>() { 1 });

Here the data parmeter is taken from the factory method parameter and passed down to the Container constructor.

Upvotes: 1

Related Questions