Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens to using statement when I move to dependency injection

Tags:

I am currently using the following code:

public class MyProvider {     public MyProvider()     {     }      public void Fetch()     {         using (PopClient popClient = new PopClient())         {             ....         }     } } 

Because I want to be able to unit test the Fetch method and due to the fact that I can't mock PopClient, I created an interface and a wrapper class that calls into PopClient. My updated code looks like:

public class MyProvider {     private readonly IPopClient popClient;      public MyProvider(IPopClient popClient)     {         this.popClient = popClient;     }      public void Fetch()     {         using (var pop3 = popClient)         {             ....         }     } } 

I am using Ninject for dependency injection and I am not quite sure what kind of effect the using statement will have in the updated code since Ninject already created an instance of PopClient and injected it into the constructor.

Will the using statement dispose of pop3 object and leave the popClient object alone so Ninject can handle it or will the using statement interfere with Ninject?

What is the proper approach in this case? Any insight would be very helpful.

like image 203
Thomas Avatar asked Sep 10 '12 22:09

Thomas


People also ask

Does dependency injection break encapsulation?

DI does violate encapsulation, and this can be avoided.

What is the main goal when we use dependency injection in our code?

The goal of the dependency injection technique is to remove this dependency by separating the usage from the creation of the object. This reduces the amount of required boilerplate code and improves flexibility.

What problem does dependency injection solve?

But when using dependency injection (DI), we can change the Wheels at runtime (because dependencies can be injected at runtime rather than at compile time). You can think of DI as the middleman in our code who does all the work of creating the preferred wheels object and providing it to the Car class.

Which is the right way to inject dependency?

Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed. By using the guard pattern, you can use the class with confidence, knowing that the field variable storing that dependency will be a valid instance.


2 Answers

The pop3 variable will be given the same reference to an IPopClient object that popClient has, so when the using statement is over, the object referred to by both the local and instance variables will be Dispose()d, probably placing it in an inconsistent state for further use.

If you want to use multiple instances of IPopClient, one per Fetch() call, what you should do is inject a "factory method":

public class MyProvider {     private readonly Func<IPopClient> createPopClient;      public MyProvider(Func<IPopClient> popClientFactory)     {         this.createPopClient = popClientFactory;     }      public void Fetch()     {         using (var pop3 = createPopClient())         {             ....         }     } } 

Now, when you call Fetch(), it will execute the factory method which will return a new reference to an IPopClient, which can be used and then disposed of without affecting any other call to that method.

AutoFac supports injecting factory methods for registered types without any additional setup (hence it's name, I think); I believe when configuring a Ninject container you are required to explicitly register a "getter" as the factory method for a given return type (which can be as simple as a lambda ()=>new PopClient() or it can use a call to the container's resolution method).

like image 136
KeithS Avatar answered Sep 27 '22 01:09

KeithS


When setting up your bindings, declare the scope:

https://github.com/ninject/ninject/wiki/Object-Scopes

Ninject will call dispose on the objects it created for you, so make sure you write up your dispose methods in any objects you give to Ninject to handle.

like image 35
Gromer Avatar answered Sep 26 '22 01:09

Gromer