CodeProject
For me, Dependency Injection used to be this wild crazy slick design pattern that I could probably never implement. Well, I was recently on a project for a client that ended up being a perfect situation for a Dependency Injection type implementation. The system was comprised of several assemblies that contained their own implementation. Of course that part is not foreign to me nor should it be to any mediocre developer. However, we ran into the issue of needing to add more of these assemblies in the future and the possibility of removing some. This all needed to happen without re-building/re-deploying the entire solution. Thus.....Dependency Injection. So I taught it to myself.
In the project I was on, we ended up using an
Abstract class as our base instead of an Interface. Other than the preference of using Abstract classes, we found that there were some methods that could be common to several assemblies but not every one. So having an Abstract class made sense so that we could include some implementation in the class but also have the option to override it in the assemblies we needed it for.
All this to say, I have decided to play around with Dependency Injection for my Project Euler obsession.
The way I set it up was to have each Problem as its own assembly with a Common assembly and then a User Interface. In the Common assembly, I have added an Abstract class (Problem) that has one method (Answer) that returns a long. Each Problem assembly will inherit from this base Problem class and use that Answer method to return all my answers. Which brings up another reason for Abstract Classes (or Interfaces); they act as contracts for any assembly that inherit from them. This insures that as long as they implement the right method; another assembly could be added and work without any issues. However, it does not stop me from returning the wrong answer because of my problematic logic :). Anyways, my main reason for using Dependency Injection was to basically limit the amount of assemblies I had to reference in my executing assembly. That would have been a mess.
So how does it actually work? Alright, fine. I'll get to that now I guess. Here is a part of my App.Config file. This is where we will add a new assembly once created.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net">
<description>All Individual Project Euler Problems</description>
<object name="Problem001" type="ProjectEuler.Problem001.Problem001, ProjectEuler.Problem001" />
<object name="Problem002" type="ProjectEuler.Problem002.Problem002, ProjectEuler.Problem002" />
<object name="Problem003" type="ProjectEuler.Problem003.Problem003, ProjectEuler.Problem003" />
<object name="Problem004" type="ProjectEuler.Problem004.Problem004, ProjectEuler.Problem004" />
<object name="Problem005" type="ProjectEuler.Problem005.Problem005, ProjectEuler.Problem005" />
<object name="Problem006" type="ProjectEuler.Problem006.Problem006, ProjectEuler.Problem006" />
<object name="Problem007" type="ProjectEuler.Problem007.Problem007, ProjectEuler.Problem007" />
............etc etc
</objects>
</spring>
</configuration>
So this will be the only place we have the change something in order for a newly created assembly to work. (Granted that the DLL is in the executing bin folder.)
Here is the code to place in my executing assembly to grab all the configurations in the configuration file:
using Spring.Context; IApplicationContext context = ContextRegistry.GetContext();
Then I can use a for loop to grab the names of all the configured assemblies and use the 'GetObject' method to retrieve the object from the passed assembly name and cast it to the type of our Abstract class (Problem). Then viola, I call my 'Contracting Method' (Answer()) and I can get the answer to any assembly that is placed in the configuration file AND implements the Abstract class without changing my main code or re-compiling.
foreach(string problem in context.GetObjectDefinitionNames()) {
  var answer = (Problem)context.GetObject(problem);
Console.WriteLine(answer.Answer());
}
I think that just about gives a BASIC walk-through of how I have learned to use Dependency Injection.
Fun stuff.