A very good explanation of what dependency injection is can be found here.
Very short: Dependency injection allows you to decouple your code and to make it more unit test friendly.
Another commonly used phrase for dependency injection (DI) is inversion of control (IoC).
What is a DI / IoC container?
A DI or IoC container is basically just a type map that returns a specific implementation for a requested type. To do so, it has to be told in some way what it should return if it is asked for a given type.
Most, if not all, DI Containers automatically resolve dependencies. You’ll find an example below.
The benefits are less code duplication, you specify a concrete implementation at most once and easier unit testing because you can test each component in isolation.
The only downside is the little upfront effort that is required to configure the container.
What is StructureMap?
StructureMap is a popular DI Container with a very easy to use api for both, normal use and configuration.
The mainly used method of StructureMap is in the static ObjectFactory, the methods signature is T GetInstance<T>(). This method is enough for most use cases.
StructureMaps configuration capabilities are also very interesting as they are powerful while easy to use.
You can get it and further information here.
A very basic example:
We have these interfaces:
public interface IA
{
IB B { get;}
}
public interface IB
{
IC C { get; }
}
public interface IC { }
With these implementations:
public class A : IA
{
private readonly IB _b;
public A(IB b)
{
_b = b;
}
public IB B
{
get { return _b; }
}
}
public class B : IB
{
private readonly IC _c;
public B(IC c)
{
_c = c;
}
public IC C
{
get { return _c; }
}
}
public class C : IC { }
Such a construct has a long and ugly instantiation, new A(new B(new C()))). Unit testing the class that makes this call is limited as it directly depends on A, B and C.
The other option would be to create B in A’s constructor and C in B’s but doing so would harm unit testing even more as testing A without B and B without C is impossible.
Before I show you how to configure StructureMap, you should know that StructureMap uses so called Registries for in-code configuration and that you’d normally configure it as early as possible.
In WinForms “as early as possible” might be before calling Application.Run. If you name the registry ClientRegistry, it could look like this:
public static void Main(params string[] args)
{
ObjectFactory.Initialize(x => x.AddRegistry(new ClientRegistry());
Application.Run(ObjectFactory.GetInstance<Form1>());
}
And here are two ClientRegistry implementations that would do the job for the above case:
public class ClientRegistry : Registry
{
public ClientRegistry()
{
ForRequestedType<IA>()
.TheDefaultIsConcreteType<A>();
ForRequestedType<IB>()
.TheDefaultIsConcreteType<B>();
ForRequestedType<IC>()
.TheDefaultIsConcreteType<C>();
}
}
public ClientRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.WithDefaultConventions();
});
}
Both would map IA to A, IB to B and IC to C, in implementation 1 it’s obvious but it looks like code duplication. In implementation 2 its not obvious at all, basically all it does is looking through all types in the calling assembly and to map those types that conform to the default conventions. The default convention is mapping interfaces to classes with the same name just without the leading I.
All you have to do now is call ObjectFactory.GetInstance<IA>(), in this case you’ll get an instance of A.
Dependency Injection with StructureMap | Coding Efficiency…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
依赖注入 StructureMap | Coding Efficiency…
9efish.感谢你的文章 – Trackback from 9eFish…
[...] Dependency Injection with StructureMap – Following on from his exploration of the concepts behind SOLID, Sebastian at Coding Efficiency looks into Dependency injection using the StructureMap framework [...]