Jim Weirich has an excellent article on Dependency Injection for Ruby. I decided to take the design pattern and translate it to C# code to see how it would feel under C#, and see how this pattern holds up in relatively large projects. I’ve attached the C# code along with some NUnit tests to this posts.
I’ve been experimenting with this pattern in a relatively large project lately (in C#), and I’ve found it to be useful in the scenarios that it solves – creating objects. I’ve found that this is a good pattern to use rather than Abstract Factory, because it gives you the factory-ness of Abstract Factory yet does it without running into the dependency issue. As with Abstract Factory, the manner in which your client code can get an instance of the Dependency Injection container varies – I tried various methods (passing it through constructors, having a global static accessor like the Singleton pattern, storing it in TLS, etc), and each flavor has different pros and cons – you’ll have to find the flavor that fits you best.
The other thing I like about dependency injection is that it is essentially a pattern of Abstract Factory – so you can replace the implementation of your production dependency injection with a test one and you will be able to insert mock objects through the container.
I included the C# implementation that I put together in this post.
The C# implementation differs a bit from the Ruby implementation because I tried to make it “feel” right in .NET:
- I used GUIDs instead of strings as the key (hey, I used to be and still program a lot of COM).
- Because of #1, I added methods that registered and did lookups based on types, so that you can write di.register< MyType >( instanceOfMyType ) and do a lookup by doing di.get <MyType>() so you can eschew the keys altogether.
- However, #2 requires that you know the types, so I also provided a method which gets and object and casts it to the type specified: di.get< CastToThisInterface >( someGuid ).
Let me explain #3. Since #2 requires that the client code has access to the types provided by the dependency injector. Again, this could be my COM-dark-side seeping in again, but I definitely prefer separating interface and implementation. But I couldn’t think of a clean way to register a type and have it available to look up by interface (since for any moderately sized application you’re bound to have interface conflicts if you used the interfaces as the key), so for now, what I’ve done is allow a type to be specified to cast the resulting object to.
If you have any ideas or comments, feel free to let me know