I still need help understanding why Ninject can be better than manual DI

This is an extension of the question. Why do I need an IoC container and not a simple DI code?

I studied Ninject and came up with the following example: the example goes through the manual way to execute DI and Ninject to execute DI:

class Program { static void Main(string[] args) { NinjectWay(); ManualWay(); Console.ReadKey(); } private static void ManualWay() { Console.WriteLine("ManualWay***********************"); IWeapon sword = new Sword(); Samurai samurai = new Samurai(sword); Console.WriteLine(samurai.Attack("ManualWay...")); // change weapon IWeapon dagger = new Dagger(); samurai.Weapon = dagger; Console.WriteLine(samurai.Attack("ManualWay...")); IWeapon weapon = new Shuriken(); IWarrior ninja = new Ninja(weapon); Console.WriteLine("Manual way.. inject shuriken when a ninja. " + ninja.Weapon.Name); IWarrior ninja2 = new Ninja(weapon); } private static void NinjectWay() { Console.WriteLine("NinjectWay***********************"); IKernel kernel = new StandardKernel(); kernel.Bind<IWeapon>().To<Sword>(); var samurai = kernel.Get<Samurai>(); Console.WriteLine(samurai.Attack("NinjectWay...")); kernel.Rebind<IWeapon>().To<Dagger>(); samurai = kernel.Get<Samurai>(); Console.WriteLine(samurai.Attack("NinjectWay...")); kernel.Bind<IWeapon>().To<Shuriken>().WhenInjectedInto<Ninja>(); var ninja = kernel.Get<Ninja>(); ninja.OffHandWeapon = new ShortSword(); Console.WriteLine("Conditional Injection..."+ninja.Weapon.Name); Console.WriteLine("Conditional Injection: OffhandWeapon = " + ninja.OffHandWeapon.Name); var ninja2 = kernel.Get<Ninja>(); Console.WriteLine("Conditional Injection..." + ninja2.Weapon.Name); Console.WriteLine("Conditional Injection: OffhandWeapon = " + ninja2.OffHandWeapon.Name); Console.WriteLine(""); } } 

I heard that benefits arise when the scale of a project increases, but I don’t see it. Help me understand this better. Provide more examples in C # / Ninject and help me understand where the benefits really become apparent.

+7
source share
4 answers

Unlike other answers, offer Ninject not mainly about making your code more robust. This is a dependent injection that makes your code more testable! Dependency injection can be used without an IoC container, creating everything in the trading posts. But I am sure that it is easy to replace some parts for integration tests (do not use Ninject in unit tests) - a good side effect.

IoC containers, such as Ninject, are mainly about combining your classes into working software. In small projects, this can easily be done with the help of some plants. But as your application grows, factories become more complex. Imagine an application that has various services, some of which are reused, others are created for each use. Some of the services are also used by several components.

If you use an IoC container, you must determine exactly once how you get the service instance and what its life cycle is. On the other hand, in the factory, you need to specify how to get an instance for each class that needs an instance (for example, the new MyServiceFactory (). CreateInstance ()). In addition, you must manage the life cycle manually.

This means that as the project grows, the IoC container configuration grows linearly with the size of the project. But on the other hand, the factory is growing more pronounced, as, for example, there are services that are used throughout the application (for example, user auth).

BTW: Your example is not very good, because Rebinding is not a common action. Typically, the configuration is performed only once at application startup.

+5
source

One of the benefits is testing.

You can bind Sword to IWeapon in your production code, and FakeSword to IWeapon in your test build. This is useful when you need to check out something that is dependent on IWeapon, but you really don't need a real sword.

For example, instead of Sword and IWeapon, you have IDataContext and DataContext. Excellent in your production code when you need to connect to the database. But for unit tests, you probably don't want to hit the database for various reasons (performance, inconsistent data, etc.). This way you connect the FakeDataContext to your IDataContext. Now you have control over the simulation of database activity for testing.

0
source

BIG QUESTION!

BIG BIG wins IMHO when your code that requests instances does not know or care about what the actual implementations are. This is most obvious in ridicule - your mocking structure can set Ninject to return the mocking Ninja's, Sword's, and Samarai that implement behaviors that you expect in completely different ways.

I have a repository layer, for example, which is dependent on IoC to access the data store. For testing, this data warehouse is a hand-made collection of objects. Web services are used for remote access to the data warehouse. Locally this is SQL. The repository simply requests an IDataStore from the IoC and gets everything that has been configured for maintenance.

Does it help?

0
source

The main advantage of Ninject is that you do it manually, because someone else has done a lot of abstractions for you. It’s clear that you could reproduce a similar thing by writing similar Ninject code (something to create objects based on interface types), which will allow you to separate your object construction from the object logic, but Ninject (and other libraries) are all set up a lot heavy works for you, so if you are not going to add something new, why do you want to create it all again?

The comparison you got in your question does not really reflect the way I expected Ninject to be used. You bind and bind the same method as using objects. I was expecting the container to be set up somewhere else. This allows you to change the design (for example, to make it easier to test by creating mock objects) without changing the code that actually uses the constructed object.

0
source

All Articles