Note: To access the latest source and binary releases for the LinFu v2.0 Framework directly from the SVN repository, click here.
Introduction
In this part of the series, I'll show you how you can use LinFu.IOC's various injection capabilities to automatically inject your dependencies into type members such as constructors, methods, properties, and fields, and I'll even show you how you can use it to perform dependency injection on types that you don't even own.
Overview
In the first part of the series, I showed you how you can use LinFu to configure the ServiceContainer
class to create (and consume) your custom types, and in this part of the series, I'll show you how LinFu.IOC can remove most of the boilerplate code that is typically associated with using dependency injection and inversion of control containers. I'll also show you what it would look like if it were done by hand, as well as show you how LinFu can do the same thing without forcing you to type all those lines of code all by yourself.
Background
If you're familiar with standard object-oriented programming principles but you're new to dependency injection and inversion of control, then there's a good chance that you might already be practicing DI/IOC, albeit without any of the jargon or terminology. Needless to say, if you know how to work with primitive types, interfaces, abstract classes, and understand basic polymorphism and inheritance, then the concepts that you will see here will be nothing new to you. In fact, you're probably already practicing inversion of control if you apply these few simple rules to your code:
Rule #1: Always depend on interfaces or abstract classes to do the job.
This means that you should never reference or directly instantiate any concrete classes in your code. What you need to do is change any concrete class dependencies into abstract classes and make sure that you don't create any concrete types in your code. For example, let's suppose that we had two classes--a Car
and a concrete RaceCarEngine
class. A naive implementation would probably look like this:
public class Car
{
private RaceCarEngine _engine = new RaceCarEngine();
public void Park()
{
_engine.Stop();
Console.WriteLine("The car is now parked.");
}
public void Move()
{
_engine.Start();
Console.WriteLine("The car is moving!");
}
}
public class RaceCarEngine
{
public void Stop()
{
Console.WriteLine("Engine stopped");
}
public void Start()
{
Console.WriteLine("Engine started);
}
}
Naivete
The problem with the naive implementation above is that the Car
class is hard-wired to use only the RaceCarEngine
class, and that might cause us some future headaches if we wanted to convert this hypothetical model into something that can produce an entire family of cars that have no use for a RaceCarEngine
class. What we need to do is refactor the concept of a generic-Engine
class into something more reusable, and that's where the IEngine
interface comes in handy:
public interface IEngine
{
void Start();
void Stop();
}
Once the IEngine
interface is in place, we can now rewrite the Car
class to use the new IEngine
interface:
public class Car
{
private IEngine _engine = new RaceCarEngine();
public void Park()
{
_engine.Stop();
Console.WriteLine("The car is now parked.");
}
public void Move()
{
_engine.Start();
Console.WriteLine("The car is moving!");
}
}
Naivete, Part Deux
Although the Car
class above has been modified to use an IEngine
interface instead of a RaceCarEngine
class, the Car
class is still hardwired to use a RaceCarEngine
and there doesn't seem to be a way to plug in our own implementation of the IEngine
interface into the current version of the Car
class itself. There has to be some way to initialize a Car
class instance so that it uses a specific type of engine, and that's where using constructors to initialize the Car
class comes in handy:
public class Car
{
private IEngine _engine;
public Car(IEngine engine)
{
_engine = engine;
}
public virtual void Park()
{
_engine.Stop();
Console.WriteLine("The car is now parked.");
}
public virtual void Move()
{
_engine.Start();
Console.WriteLine("The car is moving!");
}
}
Once the reference to the
RaceCarEngine
class has been removed, here is the client code to initialize the
Car
class:
var myCar = new Car(new RaceCarEngine());
myCar.Move();
Control, Inverted
As you can see from the examples above, the Car
class is no longer responsible for deciding which implementation of the IEngine
interface will be used. Instead, the client code is now responsible for determining which concrete implementation of the IEngine
interface should be used when the Car
class is initialized. The client code (rather than the Car
class) "controls" the IEngine
implementation, and that's why it's called the inversion of control. In traditional OOP code, the Car
class would typically have control over which IEngine
implementation should be used, and now that the client has full control, the modified Car
class has taken that concept and turned it upside down by allowing the client to insert its own external IEngine
implementations into the Car
class itself. This approach allows us to extend the Car
class by allowing the client code to "inject" new types of IEngine
implementations without affecting the Car
class implementation. For example, I can create three different types of Car
class instances just by using the following code:
var familyCar = new Car(new FamilyCarEngine());
var oldCar = new Car(new OldCarEngine());
var sportsCar = new Car(new SportsCarEngine());
Caveat Implementor
Of course, the only problem with the approach above is that the client code needs to know which concrete IEngine
class implementation(s) it should use at compile time, and that might make things difficult if we need to add new IEngine
types to the model without recompiling the whole application. More importantly, this approach forces the client to know the different types of IEngine
implementations, and the tight coupling between the client code and the concrete IEngine
classes effectively negates one of the purposes for using inversion of control in the first place, which is loose coupling. Needless to say, code that is loosely coupled is easier to maintain, modify, and extend, and in this case, we've come across quite an extensibility problem since there doesn't seem to be a way to use the Car
class without forcing the client to know exactly which IEngine
implementation it should use when creating the Car
class itself. There has to be some way to let the client code use the Car
class without forcing it to know of any specific IEngine
implementation, and that's what we'll cover in the next section.
Rule #2: Let the client code decide which concrete implementation of your interfaces (or abstract classes) should be used at runtime, not compile time.
In order to solve the tight coupling problem, the client needs to be able to resolve which IEngine
instance should be used at runtime. Ideally, the client code should only be concerned with obtaining a valid IEngine
reference without any regard as to how (or where) that IEngine
instance is constructed, as shown in this hypothetical example:
IEngine engine = SomeCustomIEngineLookupMethod();
var familyCar = new Car(engine);
familyCar.Move();
The Self-Made Family Car
Assuming that there is some way to have the client dynamically resolve an IEngine
interface implementation at runtime using some resolution method, the task of creating a IEngine
and consuming it with a Car
instance becomes practically trivial because both the client code and the Car
class no longer need to know anything about how a IEngine
instance is created in order to use the IEngine
instance itself. Instead, the onus for creating and initializing the IEngine
instance falls on the 'hypothetical' IEngine
lookup method. In general, that same lookup method should be able to give the client nearly any type it requests at runtime, including IEngine
instances. It should also be smart enough to understand and determine which specific type instances should be created based on the context of the request given by the client. Based on the examples that I gave above, it's clearly evident that inversion of control in itself isn't enough; there has to be some component in the middle (per se) that handles the type resolution (and instantiation) for the client.
Factories to the Rescue?
From the client code's perspective, it really doesn't matter how the IEngine
instance is resolved, provided that it obtains a valid IEngine
instance prior to instantiating the car class. In this case, we somehow need to instantiate a IEngine
instance, and at first glance, a factory looks like what we need:
public class CarEngineFactory
{
public virtual IEngine CreateInstance()
{
return new RaceCarEngine();
}
}
The client code, in turn, would look like:
var factory = new CarEngineFactory();
IEngine engine = factory.CreateInstance();
var familyCar = new Car(engine);
familyCar.Move();
The Dilemma
At first, it seems that the IEngine
type resoution problem can be easily solved by providing custom derived instances of the CarEngineFactory
class and then have the client code call the virtual CreateInstance()
method so that the IEngine
instance can be dynamically resolved at runtime. One of the problems with this approach, however, is that it only applies to IEngine
instances, and this can become quite cumbersome if you want to apply this approach to all the abstract types in your application. Creating a factory class for each abstract type is clearly not an option if, for example, your application has over several hundred abstract types or interfaces and you want to be able to manage the instantiation of each one of the types that your application will use. There has to be some way to create these multiple factory types without having to force you to manually write dozens of factories just so that you can you can have the benefits that inversion of control can provide. To make things even more complicated, the IEngine
factory classes in the example above are also statically created using the new
operator, and that means that even the factory classes themselves are subject to the same static limitations that were imposed on the IEngine
instances used by the Car
factory.
Recursive Dilemma, Meet Thyself
In order to effectively solve this problem, we need to make sure that both the IEngine
as well as its factories are dynamically resolved at runtime. These IEngine
factories have to be dynamically resolved at runtime so that we can add new IEngine
factories at will without having to recompile the application. In general, this "dual" dynamic type/factory resolution approach also has to apply to other types in an application so that the app (as a whole) will benefit by using inversion of control. For example, there also has to be a way to dynamically create the Car
class using the resolved IEngine
instance:
IEngine engine = factory.CreateInstance();
var familyCar = new Car(engine);
Finding the Constructor
This scenario with the Car
class might seem familiar given that the Car
class itself is also a type that might be resolved at runtime. There could be an infinite number of Car
variations, and there has to be a way to add new Car
types with every new IEngine
type that comes with a particular Car
type. Moreover, assuming that we can dynamically determine which Car
-derived type should be used, there's still the problem of determining which constructor should be used in instantiating that type. For example, let's assume the FamilyCar
class has the following constructors:
public class FamilyCar : Car
{
public FamilyCar() : base(new FamilyCarEngine())
{
}
public FamilyCar(int doors) : this()
{
}
public FamilyCar(IEngine engine, int doors)
{
}
}
Inversion of Control = Inversion of Sanity?
Given that we need to be able to dynamically decide which FamilyCar
constructor should be used to instantiate the FamilyCar
class, it's fairly obvious that we've run into a scalability problem since our hypothetical application will inevitably need to create several types at runtime. Each one of these dynamically-instantiated types will have a different set of constructors, and choosing the appropriate constructor at runtime given the infinite number of additional types poses a serious challenge since we have no knowledge of any of the types that might be created until the program runs. In other words, while static inversion of control itself is a novel concept, following its principles alone is not enough to meet the scalability requirements in any application. Indeed, what many other proponents of inversion of control have failed to mention (or otherwise implicitly mentioned) is that inversion of control can scale if and only if the dependencies above are dynamically resolved for you by some other component. These components are typically called Inversion of Control Containers, and for the most part, they're responsible for implementing most of the boilerplate code that I mentioned above. LinFu.IOC is the lesser known among all the other containers (such as Castle, Ninject, Spring, AutoFact, Unity, and MEF) , and despite its relative obscurity, this series will show you how its features and flexibility rivals any of its container bretheren. With that in mind, let's jump straight into the code!
Using the Code
A Sample Model
Like other inversion of control frameworks, LinFu handles most of the boilerplate code that you normally would need to instantiate and inject dependencies into your types. For example, let's assume that we have the following interfaces and classes defined in another sample model:
public interface IWeapon
{
int Damage { get; }
}
public interface IAttacker
{
void Attack(string target);
}
public interface IDefender
{
void DefendAgainst(IAttacker attacker);
}
public interface IWarrior : IAttacker, IDefender
{
string Name { get; set; }
int Rank { get;set; }
}
public interface IArmy : IAttacker, IDefender
{
string Name { get; set: }
IEnumerable<IWarrior> Warriors { get; }
}
Defining the Concrete Class Army
Of course, these interfaces would be completely useless without a corresponding set of concrete class implementations. Here's where the Samurai
class comes in handy:
public class Samurai : IWarrior
{
public Samurai(IWeapon weapon, string name, int rank)
{
Weapon = weapon;
Name = name;
Rank = rank;
}
public string Name { get; set; }
public int Rank { get;set; }
public IWeapon Weapon { get;set; }
public void Attack(string target)
{
Weapon.Hit(target);
}
public void DefendAgainst(IAttacker attacker)
{
Console.WriteLine("Samurai '{0}': Defending against {1}", Name, attacker);
}
}
...and here is the corresponding IArmy
implementation:
public class WarriorArmy : IArmy
{
private IEnumerable<IWarrior> _warriors;
public WarriorArmy(IEnumerable<IWarrior> warriors)
{
_warriors = warriors;
}
public string Name { get;set; }
public void Attack(string target)
{
foreach(var warrior in _warriors)
{
warrior.Attack(target);
}
}
public void DefendAgainst(IAttacker attacker)
{
Console.WriteLine("The army '{0}' is defending against {1}", Name, attacker);
foreach(var warrior in _warriors)
{
warrior.DefendAgainst(attacker);
}
}
public IEnumerable<iwarrior> Warriors
{
get { return _warriors; }
}
}
Building the Army
Normally, the most straightforward approach to build this army would look something like this:
var warriors = new List<IWarrior>();
var warriorCount = 10000;
for(int i = 0; i < warriorCount; i++)
{
IWeapon someWeapon = ...
warriors.Add(new Samurai(someWeapon, "Anonymous", 1));
}
IArmy army = new WarriorArmy(warriors);
Manual Injection = Manual Headache
Although the example above is the simplest way to build an army class instance, the example itself is completely devoid of any code that would let you decide how the IWeapon
dependency should be injected into Samurai
class. More importantly, the example only injects Samurai
class instances into the army itself, and that could cause some problems if you wanted to add additional IWarrior
-derived types to this mythical army. In order to keep the application flexible, we need to be able to automatically inject both the IWeapon
and the multiple IWarrior
instances into the proper class constructors at runtime without having to specify the concrete classes that will ultimately implement those interfaces. Needless to say, manually writing such injection routines can be a daunting task. Fortunately for us, however, LinFu.IOC makes this task practically trivial, and this brings us to the next section:
Constructor Injection
Constructor-Agnostic
In its most basic form, LinFu.IOC allows you to instantiate practically any .NET type using the contents of an existing ServiceContainer
instance without forcing you to specify which constructor should be used to instantiate that type. For example, let's suppose that the Samurai
class has the following additional constructor:
public Samurai(IWeapon weapon)
{
}
Normally, you would have to manually decide which IWeapon
instance to use by hand, but in this case, LinFu.IOC can do it for you in relatively fewer lines of code:
var container = new ServiceContainer();
container.LoadFromBaseDirectory("*.dll");
var warriorType = typeof(Samurai);
var samurai = (ISamurai)warriorType.AutoCreateFrom(container);
As you can see from the example above, LinFu.IOC adds the AutoCreateFrom
method to System.Type
instances to make it easier to instantiate any given type without having to worry about which constructor should be used you or the container itself. What makes this particularly interesting is the fact that the Samurai
class doesn't even need to be registered within the ServiceContainer
instance itself in order for the container to determine which constructor should be used or injected during instantiation. In other words, it just works.
Dealing with Multiple Constructors
Now that the Samurai
class has more than one constructor with an IWeapon
dependency, we have run into quite a bit of a problem: exactly how does the container know which constructor should be used to instantiate the given Samurai
type? For example, let's assume that the Samurai
class has the following constructors:
public Samurai(string name, int rank)
{
}
public Samurai(IWeapon weapon)
{
}
public Samurai(IWeapon weapon, string name, int rank)
{
}
It's one thing to have constructors that have parameters that can be instantiated by the container using the second constructor, but the problem is that there doesn't seem to be a way to manually have the container select the first or third constructor when creating the Samurai
type. Fortunately, this is where the same AutoCreateFrom
extension method comes in handy:
var container = new ServiceContainer();
var warriorType = typeof(Samurai);
var name = "Musashi";
var rank = 1;
var samurai = (ISamurai)warriorType.AutoCreateFrom(container, name, rank);
container.AddService<IWeapon>(new SamuraiSword());
samurai = (ISamurai)warriorType.AutoCreateFrom(container, name, rank);
The AutoCreateFrom
method allows you to pass additional arguments to the container so that it can automatically determine which constructor should be used when instantiating your type. In the example above, the container called the first constructor when there was no IWeapon
instance available, and the container automatically selected the third constructor once an IWeapon
instance was added to the container itself. In other words, LinFu.IOC's ServiceContainer
class can automatically "infer" the correct constructor by combining the services currently available in the container with the additional arguments that you supply in the actual AutoCreateFrom
method call. What makes this even better is the fact that the container can resolve any constructor from an almost infinite number of constructor signatures declared on a target type. In short, LinFu.IOC handles all the boilerplate constructor resolution routines for you so that you can move on to do the more important tasks, such as developing the rest of your application.
Building the Warrior Army v2.0
Now that we can make Samurai
class instances without having to worry about their dependencies, we need to configure the container so that a Samurai
instance will be returned every time an IWarrior
instance is requested from the container. In addition, we need to create several IWarrior
instances so that we can instantiate the WarriorArmy
class using the following constructor:
public WarriorArmy(IEnumerable<IWarrior> warriors)
{
}
Creating Samurai v1.0
Before we create the WarriorArmy
instance, however, we'll need to configure the Samurai
class as the default implementation of the IWarrior
interface, and all it takes is a single ImplementsAttribute
declaration on Samurai
class:
[Implements(typeof(IWarrior)]
public class Samurai : IWarrior
{
}
Once the ImplementsAttribute
declaration is in place, here's how you can get the container to automatically load the Samurai
service into memory:
var container = new ServiceContainer();
container.LoadFromBaseDirectory("Samurai.dll");
If you prefer to keep LinFu's attributes out of your domain model, however, then you can use this line of code to manually add the Samurai
class to the container:
container.AddService(typeof(IWarrior), typeof(Samurai), LifecycleType.OncePerRequest);
Once the Samurai
class has been registered, here's the code that will instantiate the IWarrior
instance itself:
var warrior = container.GetService<IWarrior>("Musashi", 1);
As you can see, the code above is pretty self-explanatory, and now that we can build a single warrior, it's time to build a collection of IWarrior
instances so that we can instantiate the WarriorArmy
class.
Building the IEnumerable<IWarrior> parameter
At this point, there has to be some way to have the container construct an IEnumerable<IWarrior>
instance every time an IEnumerable<IWarrior>
. We could naively construct it ourselves by manually inserting a List<IWarrior>
and populating it with an arbitrary set of IWarrior
instances, but the problem is that we need to make sure that the collection of IWarrior
instances is only created from the container when the actual GetService
method is called. In other words, we need to have this list dynamically generated on demand, and it has to match the current IWarrior
service that resides within the container at the time of the request. At first, it seems a bit impossible given that we only have access to the container compile time. There has to be some way to dynamically access the container at runtime, and this is where LinFu.IOC's support for C# 3.0's lambda expressions makes it very interesting:
var warriorCount = 100;
Func<IFactoryRequest, IEnumerable<IWarrior>> factoryMethod =
request =>
{
var currentContainer =
request.Container;
var warriors = new List<iwarrior>();
for (int i = 0; i < warriorCount; i++)
{
var newWarrior = currentContainer.GetService<iwarrior>();
warriors.Add(newWarrior);
}
return warriors;
};
container.AddService(factoryMethod, LifecycleType.OncePerRequest);
Lambdalicious
LinFu.IOC allows you to register factory lambda expressions with the container, and this approach allows us to use the IEnumerable<IWarrior>
service without having to explicitly register an IEnumerable<IWarrior>
instance with the container itself. More importantly, this approach is much more flexible since the factoryMethod
lambda expression will be used to dynamically generate the list of IWarrior
instances at runtime. The factoryMethod
expression will be able to access whatever IWarrior
instance resides in the current container instance, and this approach will allow us to build our list of warriors without binding the factory implementation to any specific IWarrior
type or any specific container. Now that we have the list of warriors to create, we'll have to give them a set of IWeapon
instances before they rush themselves into battle without a weapon. For simplicty's sake, let's just arm them with SamuraiSword
instances, and let whatever far eastern deity sort them out:
public interface IWeapon
{
}
public class SamuraiSword : IWeapon
{
}
The corresponding code to register the SamuraiSword
instance would be:
container.AddService(typeof(IWeapon), typeof(SamuraiSword), LifecycleType.OncePerRequest);
Once the IWeapon
instances are in place, we'll need to register the WarriorArmy
class so that we can use the container to instantiate IArmy
instances:
container.AddService(typeof(IArmy), typeof(WarriorArmy), LifecycleType.OncePerRequest);
Last, but not least
At this point, the only thing left to do is create the IArmy
instance itself:
var warriorArmy = container.GetService<IArmy>();
As you can see from the example above, LinFu.IOC did most of the boilerplate work for you by injecting the necessary constructor dependencies into both the WarriorArmy
class instance and each Samurai
class instance that will be consumed by your application. The best part about the example above is the fact that the client code doesn't even need to know how the IArmy
instance is constructed in order to use an IArmy
instance. In short, LinFu.IOC allows you to construct your types regardless of whatever constructor signatures might be defined on each one of those individual types. In the example above, we've managed to reduce the boilerplate code to construct an WarriorArmy
to a single line of code, and that's the kind of simplicity that LinFu's constructor injection offers.
Property, Field, and Method Injection
Attributed Injection
In contrast, using LinFu.IOC's automatic member injection features is even easier to use than its own constructor injection features. For example, let's suppose that I have a class named Ninja
that requires an IWeapon
instance injected into one of its properties in order to function properly:
public class Ninja : IWarrior
{
[Inject]
public IWeapon Weapon { get;set; }
}
In general, LinFu.IOC supports two styles of property injection. You can use attributes to mark the properties, fields, or methods that need to be injected, or you can use LinFu's fluent interfaces to manually initialize each property, method, or field in each one of your classes. In the example above, I marked the Weapon
property with the [Inject]
attribute so that the container will automatically inject the IWeapon
dependency into the Ninja
class every time it is instantiated by the container. Here's the code that tells the container to instantiate the Ninja
class and perform the necessary member injection operations on that class instance:
var ninja = (Ninja)container.AutoCreate(typeof(Ninja));
The IServiceContainer.AutoCreate
extension method handles all the gory details of constructor, property, method, and field injection so that you can focus on what dependencies need to be injected into those respective members. If you prefer to use method or field injection, then you can easily rewrite the Ninja
class to look like this:
public class Ninja : IWarrior
{
[Inject]
public IWeapon Weapon;
[Inject]
public void StealWeapon(IWeapon weapon)
{
}
}
Again, the example above is very straightforward, and a single call to the AutoCreate
method is all you need to have the container automatically inject the necessary dependencies into both the Weapon
field and the StealWeapon
method.
Fluent Member Injection
LinFu also allows you to use fluent interfaces to perform the same property, method, and field injection features that were mentioned in the previous section. For example, here's the equivalent code to perform property, method, and field injection on the Ninja
class:
container.Initialize<Ninja>().With(container, ninja => ninja.Weapon =
container.GetService<IWeapon>());
container.Initialize<Ninja>().With(container, ninja => ninja.StealWeapon(
container.GetService<IWeapon>()));
What makes this interesting is that LinFu's fluent interface support gives you complete control over how each one of your types should be initialized. The Initialize
extension method allows you to initialize your types' members using the services that currently reside in the container. Once the container has been properly initialized, the only thing left to do is instantiate the Ninja
class:
var ninja = (Ninja)container.AutoCreate(typeof(Ninja));
Deja Vu
As you can see from the example above, the code to have LinFu instantiate and inject your types is the same no matter what member injection style you decide to use in your application. LinFu.IOC makes it easy to inject your dependencies into constructors, properties, methods, and fields without drowning you in complexity, and in the end, it will save you from having to write boilerplate code so you can focus on writing the rest of your application(s).
History
- 2/11/2009 - Article Posted