Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DI Framework: how to avoid continually passing injected dependencies up the chain, and without using a service locator (specifically with Ninject)

I need a little more help to "get" how a DI framework like Ninject moves past the basics.

Take the Ninject sample:

class Samurai {
private IWeapon _weapon;

    [Inject]
    public Samurai(IWeapon weapon) {
      _weapon = weapon;
    }

    public void Attack(string target) {
      _weapon.Hit(target);
    }
 }

Without a DI framework (i.e. the [Inject] references above) a referencing class would look something like:

class Program {
   public static void Main() { 
    Samurai warrior1 = new Samurai(new Shuriken());
    Samurai warrior2 = new Samurai(new Sword());
    warrior1.Attack("the evildoers");
    warrior2.Attack("the evildoers");
  }
}

...where you're newing up everything. Yes, you've removed the dependency in Samurai, but now you've got a dependency one step further up the chain. Simple.

With Ninject, you get rid of newing up everything by:

class Program {
  public static void Main() {
    IKernel kernel = new StandardKernel(new WarriorModule());
    Samurai warrior = kernel.Get<Samurai>();
    warrior.Attack("the evildoers");
  }
}

HOWEVER, this is my area of confusion: without making some kind of service locater to take care of efficiently newing up the applicable kernel and module (i.e. .IoC.TypeResolver.Get<>()), what is a) the best way to not have to new up kernels everywhere (service locater references everywhere?), and b) more importantly, when you've got a big long chain with dependencies with dependencies of their own, you take it to the extreme of passing injections all the way up in something that I'm sure is a serious anti-pattern (a friend called it "hot-potato dependency injection" anti-pattern).

In other words, I thought part of the DI framework magic is that you don't have to keep inserting dependencies all the way up the chain (i.e. your your first reference containing 10 parameters in its constructor, none of which have anything to do with anything until much further along the chain) - where's the magic or the solution to my confusion so that dependencies don't either continually get referenced up and up the chain, or service locater references spread everywhere.

Further muddying the waters for me is if using a DI framework, what's the best way to deal with a scenario where a referenced class needs an IList which would typically be put in the constructor (i.e. new ReferencedClass(myList)) as that, other than in simple cases like a string database connection string, doesn't fly. Just make a property and set it after newing it up/DI Framework service locating? I.e.

var referencedClass = IoC.Get<IReferencedClass>();
referencedClass.MyList = myList;

All in all, I think this is a post I'll likely be embarrassed about after I get it, but right now, I've hit my head too many times against the wall trying to determine the best approach.

like image 426
Ted Avatar asked Jan 02 '10 23:01

Ted


People also ask

Which framework is used for dependency injection?

Spring.NET is one of the popular open source frameworks for Dependency Injection. Spring.NET supports . NET 4.0, . NET Client Profile 3.5 and 4.0, Silverlight 4.0 and 5.0, and Windows Phone 7.0 and 7.1.

What is ninject dependency injection?

Ninject is a lightweight dependency injection framework for . NET applications. It helps you split your application into a collection of loosely-coupled, highly-cohesive pieces, and then glue them back together in a flexible manner.


1 Answers

As for the "hot potato" dependency issue, this doesn't have to happen. The dependency injection framework handles this for you.

For instance, if Class1 has a dependency on Class2, and Class2 has a dependency on Class3, you do not need to inject a Class3 into Class1 in order to accommodate the Class2 dependency. The kernel will walk down the dependency chain for you and will resolve the down-stream dependencies automatically (as long as all of the classes in play have been registered in the kernel) when you ask for a Class1.

Class1 depends on Class2 depends on Class3

The Class1 constructor does not need to mention Class3 at all.

As for the second issue, how or if this is accommodated is dependent on the framework. With Ninject, I think you can use the Bind().To().WithConstructorArgument() syntax to provide the new List item to the constructor.

like image 191
Eric King Avatar answered Oct 23 '22 15:10

Eric King