John Livermore
John Livermore

Reputation: 31323

How to use Ninject to create instances in child classes?

I am learning how to use nInject for a new application I am developing, and I have created the following sample code that can be copied/pasted into a simple console app. It successfully returns an instance of IFoo, but I have a question about it.

How would I modify the code to have the FooManager class create an instance of the Foo object without doing a 'new'. Does the kernal have to be injected as well? But if the kernal is injected and I change the line to read var foo = _kernel.Get<IFoo>(), isn't that introducing a service locator anti-pattern?

namespace IOCTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (IKernel kernel = new StandardKernel(new StandardModule()))
            {
                // do something with the kernal
                var mgr = kernel.Get<IFooManager>();
                var foo = mgr.GetById(1);
            }
        }
    }

    public class StandardModule : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            Bind<IDatabase>()
                .To<Database>()
                .InTransientScope();

            Bind<IFooManager>()
                .To<FooManager>()
                .InTransientScope();
        }
    }

    //******************************************************

    public interface IDatabase
    {
        object[] GetScalar(int id);
    }

    public class Database : IDatabase
    {
        public object[] GetScalar(int id)
        {
            return new object[] { "RowName" };
        }
    }

    //******************************************************

    public interface IFooManager
    {
        IFoo GetById(int id);
    }

    public class FooManager : IFooManager
    {
        private IDatabase _db;

        public FooManager(IDatabase db) { _db = db; }

        public IFoo GetById(int id)
        {
            var results = _db.GetScalar(id);
            var foo = new Foo();   // <-- HOW DO I ELIMINATE THIS DEPENDENCY?
            foo.Name = results[0].ToString();
            return foo;
        }
    }

    //******************************************************

    public interface IFoo
    {
        string Name { get; set; }
    }

    public class Foo : IFoo
    {
        public string Name { get; set; }
    }

    //******************************************************
}

Upvotes: 3

Views: 3473

Answers (2)

Remo Gloor
Remo Gloor

Reputation: 32725

First you have to think about the purpose of Foo. Is this some kind of a datacontainer or some service?

In the first case your code is perfect like it is. Datacontainers have no dependencies and shouldn't be created by the IoC container.

In the second case read about Ninject.Extensions.Factory.

http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/

https://github.com/ninject/ninject.extensions.factory/wiki

Upvotes: 4

Gary.S
Gary.S

Reputation: 7131

There are a couple ways to eliminate that dependency. You could do the same thing you did with the Database dependency and use constructor injection. You could do property injection (https://github.com/ninject/ninject/wiki/Injection-Patterns). Another way, and perhaps what you are looking for, would be service location. To do that you can update your FooManager ctor to require an IKernel. This will be resolved automatically and you can then use the kernel that is passed in to get Foo.

public class FooManager : IFooManager
{
    private IDatabase _db;
    private IKernel _kernel;

    public FooManager(IDatabase db, IKernel kernel) { _db = db; _kernel = kernel;}

    public IFoo GetById(int id)
    {
        var results = _db.GetScalar(id);
        // var foo = new Foo();   // <-- HOW DO I ELIMINATE THIS DEPENDENCY?
        var foo = kernel.Get<IFoo>(); // Like this perhaps
        foo.Name = results[0].ToString();
        return foo;
    }
}

Upvotes: 2

Related Questions