Other answers are great, but I would also like to point out this Dependency Injection Implementation using the Ninject article .
This is one of the best articles I've ever read that explains Dependency Injection and Ninject with a very elegant example.
Here is a snippet of the article:
Below the Interface will be implemented by ours (SMSService) and (MockSMSService), basically the new interface (ISMSService) will expose the same behavior of both services in the form of code below:
public interface ISMSService { void SendSMS(string phoneNumber, string body); }
(SMSService) to implement the interface (ISMSService):
public class SMSService : ISMSService { public void SendSMS(string mobileNumber, string body) { SendSMSUsingGateway(mobileNumber, body); } private void SendSMSUsingGateway(string mobileNumber, string body) { Console.WriteLine("Sending SMS using gateway to mobile: {0}. SMS body: {1}", mobileNumber, body); } }
(MockSMSService) with a completely different implementation using the same interface:
public class MockSMSService :ISMSService { public void SendSMS(string phoneNumber, string body) { SaveSMSToFile(phoneNumber,body); } private void SaveSMSToFile(string mobileNumber, string body) { Console.WriteLine("Mocking SMS using file to mobile: {0}. SMS body: {1}", mobileNumber, body); } }
we need to implement a change for our class constructor (UIHandler) to pass a dependency through it, using this code that uses (UIHandler), it can determine which specific implementation (ISMSService) to use:
public class UIHandler { private readonly ISMSService _SMSService; public UIHandler(ISMSService SMSService) { _SMSService = SMSService; } public void SendConfirmationMsg(string mobileNumber) { _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!"); } }
Now we need to create a separate class (NinjectBindings), which inherits from (NinjectModule). This class will be responsible for resolving dependencies at runtime, and then override the load event that is used to configure the binding in it. The good thing about Ninject is that we donโt need to change our code in (ISMSService), (SMSService) and (MockSMSService).
public class NinjectBindings : Ninject.Modules.NinjectModule { public override void Load() { Bind<ISMSService>().To<MockSMSService>(); } }
Now in the user interface form code, use the link for Ninject, which will determine which implementation to use:
class Program { static void Main(string[] args) { IKernel _Kernal = new StandardKernel(); _Kernal.Load(Assembly.GetExecutingAssembly()); ISMSService _SMSService = _Kernal.Get<ISMSService>(); UIHandler _UIHandler = new UIHandler(_SMSService); _UIHandler.SendConfirmationMsg("96279544480"); Console.ReadLine(); } }
Now the code uses Ninject Kernal to solve all the chains of dependencies, if we want to use a real service (SMSService) in Release mode (in a production environment) instead of a mock one, we need to change to Ninject (NinjectBindings) only to use the correct implementation or using the #if directive DEBUG as shown below:
public class NinjectBindings : Ninject.Modules.NinjectModule { public override void Load() { #if DEBUG Bind<ISMSService>().To<MockSMSService>(); #else Bind<ISMSService>().To<SMSService>(); #endif } }
Now our binding class (NinjectBindings) lives at the top of our entire execution code, and we can easily manage the configuration in one place.
Also see What is control inversion? Some very simple examples are mentioned for understanding IoC.