Ben Aaronson
Ben Aaronson

Reputation: 6975

Mapping instance to object in Ninject bindings

I think this is a relatively straightforward scenario in Ninject but I've been having difficulty finding the right terminology to search for it.

I want to do something like:

public interface IClass
{
    IInner Inner { get; }
}

public class ConcreteClass : IClass
{
    public ConcreteClass(IInner inner)
    {
        Inner = inner;
    }

    public IInner Inner {get; private set;}
}

public class Test
{
    private BindingObject _binding {get; set;}

    private override BindingTest()
    {
        //These two lines need some extra configuration
        Kernel.Bind<IClass>().To<ConcreteClass>();
        Kernel.Bind<IInner>().To<ConcreteInner>();

        _binding = new BindingObject(1);
        IClass class1 = Kernel.Get<IClass>();

        _binding = new BindingObject(2);
        IClass class2 = Kernel.Get<IClass>();

        _binding = new BindingObject(1);
        IClass class3 = Kernel.Get<IClass>();

       //The bindings should be set up such that these asserts both pass
       Assert.AreSame(class1.Inner, class3.Inner);
       Assert.AreNotSame(class1.Inner, class2.Inner);
    }
}

The implementation of BindingObject doesn't matter as this is just a toy example, the idea is just that two BindingObjects will compare equal if and only if the int passed to their constructor is the same. Likewise, the implementations of IInner and ConcreteInner don't matter.

So essentially the idea is to set up the binding such that _binding is used as a key, and every time Ninject needs to inject a new IInner, it will just return the existing instance if it has one bound to that particular _binding, and create a new one if not. Is there some straightforward in-built way to do this? If not, could I get some guidance (not necessarily a full implementation) about an approach?

Upvotes: 4

Views: 1237

Answers (1)

Anders
Anders

Reputation: 1643

Take a look at the Custom Scope .InScope(). That is exactly what you are looking for.

You provide an instance of an object (your BindingObject) to the scope func<>. This object is used as an reference when creating/retrieving instances in the kernel.

The Kernel will check if an instance of IInner exists with an reference to that object; If so return instance, otherwise create new.

Example:

Kernel.Bind<IClass>().To<ConcreteClass>();
Kernel.Bind<IInner>().To<ConcreteInner>().InScope(o => { return _binding ; });

var reference1 = new object();
var reference2 = new object();

_binding = reference1;
var class1 = kernel.Get<IClass>();

_binding = reference2;
var class2 = kernel.Get<IClass>();

_binding = reference1;
var class3 = kernel.Get<IClass>();

Here class1 and class3 will have the same reference of IInner, whereas class2 will have another reference.

More info at: http://www.ninject.org/wiki.html under Ninject -> Using Ninject -> Object Scopes. Look near the bottom. and an little article about scopes: http://bobcravens.com/2010/03/ninject-life-cycle-management-or-scoping/

//Cheers

Upvotes: 3

Related Questions