Mike Bailey
Mike Bailey

Reputation: 12817

How can I bind the same dependency to many dependents in Ninject?

Let's I have three interfaces: IFoo, IBar, IBaz. I also have the classes Foo, Bar, and Baz that are the respective implementations.

In the implementations, each depends on the interface IContainer. So for the Foo (and similarly for Bar and Baz) the implementation might read:

class Foo : IFoo
{
    private readonly IDependency Dependency;

    public Foo(IDependency dependency)
    {
           Dependency = dependency;
    }

    public void Execute()
    {
         Console.WriteLine("I'm using {0}", Dependency.Name);
    }
}

Let's furthermore say I have a class Container which happens to contain instances of the IFoo, IBar and IBaz:

class Container : IContainer
{
    private readonly IFoo _Foo;
    private readonly IBar _Bar;
    private readonly IBaz _Baz;

    public Container(IFoo foo, IBar bar, IBaz baz)
    {
        _Foo = foo;
        _Bar = bar;
        _Baz = baz;
    }
}

In this scenario, I would like the implementation class Container to bind against IContainer with the constraint that the IDependency that gets injected into IFoo, IBar, and IBaz be the same for all three. In the manual way, I might implement it as:

IDependency dependency = new Dependency();
IFoo foo = new Foo(dependency);
IBar bar = new Bar(dependency);
IBaz baz = new Baz(dependency);
IContainer container = new Container(foo, bar, baz);

How can I achieve this within Ninject?

Note: I am not asking how to do nested dependencies. My question is how I can guarantee that a given dependency is the same among a collection of objects within a materialized service.

To be extremely explicit, I understand that Ninject in it's standard form will generate code that is equivalent to the following:

IContainer container = new Container(new Foo(new Dependency()), new Bar(new Dependency()), new Baz(new Dependency()));

I would not like that behavior. I cannot have the Dependency created as a singleton either. Specifically, this means that if I have multiple requests to GetService<IContainer>, the Ninject calls should be semantically equivalent to the following manual injection:

var dep1 = new Dependency();
var container1 = new IContainer(new Foo(dep1), new Bar(dep1), new Baz(dep1));

var dep2 = new Dependency();
var container2 = new IContainer(new Foo(dep2), new Bar(dep2), new Baz(dep2));

Upvotes: 4

Views: 220

Answers (3)

armen.shimoon
armen.shimoon

Reputation: 6401

Here's another attempt:

public class Container : IContainer
{
    private IFoo _foo;
    private IBar _bar;
    private IBaz _baz;


    public Container(IContainerDependencies dependencies)
    {
        _foo = dependencies.Foo;
        _bar = dependencies.Bar;
        _baz = dependencies.Baz;
    }
}

public class ContainerDependencies : IContainerDependencies
{
    public ContainerDependencies(IFoo foo, IBar bar, IBaz baz)
    {
        Foo = foo;
        Bar = bar;
        Baz = baz;
    }

    public IFoo Foo { get; set; }
    public IBar Bar { get; set; }
    public IBaz Baz { get; set; }
}

public interface IContainerDependencies
{
    IFoo Foo { get; set; }
    IBar Bar { get; set; }
    IBaz Baz { get; set; }
}

Then:

var kernel = new StandardKernel();
kernel.Bind<IFoo>().To<Foo>();
kernel.Bind<IBar>().To<Bar>();
kernel.Bind<IBaz>().To<Baz>();
kernel.Bind<IContainerDependencies>().ToMethod(context =>
    {
        context.Kernel.Unbind<IDependency>();
        context.Kernel.Bind<IDependency>().ToConstant(new Dep());
        return context.Kernel.Get<ContainerDependencies>();
    });
 kernel.Bind<IContainer>().To<Container>();

Upvotes: 1

horgh
horgh

Reputation: 18533

Use ToConstant method to specify exact instance to bind to. If there is an opportunity you can use Unbind to rebind to another instance:

        IKernel nKernel = new StandardKernel();

        nKernel.Bind<IFoo>().To<Foo>();
        nKernel.Bind<IBar>().To<Bar>();
        nKernel.Bind<IBaz>().To<Baz>();
        nKernel.Bind<IContainer>().To<Container>();

        nKernel.Bind<IDependency>().ToConstant(new Dependency());            

        Container c = nKernel.Get<Container>();
        //utilize the container...

        nKernel.Unbind<IDependency>();
        nKernel.Bind<IDependency>().ToConstant(new Dependency());

        c = nKernel.Get<Container>();
        //utilize the container...

Upvotes: 3

armen.shimoon
armen.shimoon

Reputation: 6401

EDIT:

How about this?

kernel.Bind<IContainer>().ToMethod(context =>
            {
                IDependency dependency = new Dep();
                IFoo foo = new Foo(dependency);
                IBar bar = new Bar(dependency);
                IBaz baz = new Baz(dependency);
                return new Container(foo, bar, baz);
            });

Upvotes: 1

Related Questions