Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

LinFu.IOC 2.0 in Five Minutes (Part 2 of n): Constructor, Field, Method, and Property Injection

0.00/5 (No votes)
11 Feb 2009 1  
The second article in a series of articles that describes how you can LinFu.IOC 2.0's dependency injection capabilities to extend your application(s).

LinFu.png

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
{
    // Note the hardcoded reference to the RaceCarEngine class
    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
{
    // The Good: The car depends on IEngine.
    // The Bad: We're still stuck with the RaceCarEngine class.
    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
{
    // The Good: The reference to the RaceCarEngine class has been removed
    // The Bad: How do you initialize the car class with a new engine if you
    // still have to specify the engine type at compile time?
    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:
// Notice that we still have to hardcode the RaceCarEngine into the Car constructor call
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());

// Do something with the new cars here...
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();

// Create and use the car here
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();

// Create and use the car here
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();

// Note: Wait...how do you dynamically create the Car class?
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) 
    {
        // Tell the warriors to attack
        foreach(var warrior in _warriors)
        {
            // This is going to hurt
            warrior.Attack(target);
        }
    }
    public void DefendAgainst(IAttacker attacker)
    {
        Console.WriteLine("The army '{0}' is defending against {1}", Name, attacker);
        foreach(var warrior in _warriors)
        {
            // This is going to hurt too
            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 = ... // Wait, where can we get a weapon instance?
    warriors.Add(new Samurai(someWeapon, "Anonymous", 1));
}

IArmy army = new WarriorArmy(warriors);
// Do something useful with the army here...
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)
{
    // Do something useful here
}

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:

// Load and configure the container
var container = new ServiceContainer();
container.LoadFromBaseDirectory("*.dll");

// This assumes that the container already has an IWeapon instance available for
// instantiation
var warriorType = typeof(Samurai);

// This will create the samurai using the constructor with the single IWeapon parameter
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) 
{
    // Constructor #1
}

public Samurai(IWeapon weapon)
{
    // Constructor #2
}

public Samurai(IWeapon weapon, string name, int rank) 
{
    // Constructor #3
}

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:

// Notice that this container doesn't yet have an IWeapon instance loaded into the
// container
var container = new ServiceContainer();

var warriorType = typeof(Samurai);

// Call Constructor #1
var name = "Musashi";
var rank = 1;
var samurai = (ISamurai)warriorType.AutoCreateFrom(container, name, rank);

// Add an IWeapon implementation to the container
// so that it will call constructor #3
container.AddService<IWeapon>(new SamuraiSword());

// This will call Constructor #3 since there is an IWeapon
// instance registered with the container; notice
// that we didn't have to change or add any code for the container
// to use the third constructor
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:

// NOTE: This assumes that your library is located in "Samurai.dll"
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:

// Create a samurai named "Musashi" with a rank of 1
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 =>
                {
                    // Access the container at runtime
                    var currentContainer =
                        request.Container;

                    var warriors = new List<iwarrior>();
                    for (int i = 0; i < warriorCount; i++)
                    {
                        // Create the IWarrior instance that currently resides in
                        // the container
                        var newWarrior = currentContainer.GetService<iwarrior>();
                        warriors.Add(newWarrior);
                    }

                    return warriors;
                };

// Generate the list of warriors at runtime by
// having the container invoke the factory method on every request
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:

// Every samurai needs a weapon of their own
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:

// This is the only line of code you'll need to create the IArmy instance
var warriorArmy = container.GetService<IArmy>();

// ...Do something useful with the army here

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
{
    // Other class members have been omitted for brevity
    [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));

// ..Use the ninja here

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
{        
    // Field Injection
    [Inject] 
    public IWeapon Weapon;         
    
    // Method injection
    [Inject]
    public void StealWeapon(IWeapon weapon) 
    {
        // Do something here
    }
    
    // ...
}

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:

// Field/Property Injection
container.Initialize<Ninja>().With(container, ninja => ninja.Weapon = 
    container.GetService<IWeapon>());

// Method Injection
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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here