Humblecoder

Caution, this blog may be ironically named

Introducing OCInject

| Comments

Update I’ve created a CodePlex project: http://ocinject.codeplex.com

I’ve been learning about Dependency Injection (DI) and Inversion of Control, one of the ways I’ve done this is by creating my own mini DI framework for use in DirLinker.  I’ve, also, looked at the big name frameworks and read lots along the way but I want to give something back to the community that has taught me so much.  So I’m releasing my tiny DI framework used in DirLinker independently as OCInject.

OK, So Why Is This Different To X

My aim when creating OCInject was to create something that can be used in small projects, single exe utilities or one off apps, where you want the advantages of a DI container but without the overhead of Castle, Autofac, et al.  So consider this DI lite, you simply take the two files, IClassFactory.cs and ClassFactory.cs, and drop them in to your project. That’s it, done, no external dependency and no XML config file. What do you get?

Features:

  • A DI Container with fluent like configuration
  • Ability to resolve constructor parameters for registered types and passed in constructor arguments
  • Runtime delegate factory generation
  • Pseudo session support via IDisposable.

The feature list is tiny and is very unlikely to grow; well maybe by one, singleton support.  It is not meant to compete with or to replace anything that already exists.

How To Use It

Basic Resolution

As I said above first thing to do is copy IClassFactory.cs and ClassFactory.cs into your project, then fill the container and resolve your type.  For example

    public interface IMyClass
    {    }  
    public class MyClass : IMyClass
    {  }  
    public class MyApp
    {
        public void Run()
        {
            IClassFactory factory = new ClassFactory();  
            factory.RegisterType<IMyClass, MyClass>();  
            IMyClass myClass = factory.ManufactureType<IMyClass>();
        }
    }

If the class has dependencies we can inject these just by specifying them as constructor arguments on our class and the container will resolve them if they are registered.  For example

public interface IMyClassWithDepend
{}  
public class MyClassWithDepend
{
    public MyClassWithDepend(IMyClass depend)
    { }
}  
public class MyApp
{
    public void Run()
    {
        IClassFactory factory = new ClassFactory();  
        factory.RegisterType<IMyClassWithDepend, MyClassWithDepend>();
        factory.RegisterType<IMyClass, MyClass>();  
        IMyClassWithDepend myClass = factory.ManufactureType<IMyClassWithDepend>();
    }
}

Auto Delegate Factories

For auto generated delegate factories we need to create a delegate that returns the contract type. Then register this with the container using the WithFactory method when registering the type. For example:

public delegate IMyClassCreatedByFactory FactoryMethodName();  
public interface IMyClassCreatedByFactory
{ }  
public class MyClassCreatedByFactory
{ }  
public class FactoryConsumer : IFactoryConsumer
{
    FactoryMethodName _Factory;
    public FactoryConsumer(FactoryMethodName factory)
    { _Factory = factory; }  
    public void DoWork()
    {
        IMyClassCreatedByFactory c = _Factory();
    }
}  
public class MyApp
{
    public void Run()
    {
        IClassFactory factory = new ClassFactory();  
        factory.RegisterType<IFactoryConsumer, FactoryConsumer>();
        factory.RegisterType<IMyClassCreatedByFactory, MyClassCreatedByFactory>()
            .WithFactory<FactoryMethodName>();  
        IFactoryConsumer myClass = factory.ManufactureType<IFactoryConsumer>();
        myClass.DoWork();
    }
}

Auto Delegate Factories With Parameters

Delegate factories can take parameters and pass them on to the constructors of objects.  This is still a bit limited because it doesn’t intelligently select the correct constructor, just the first it comes across (maybe a feature for the future :P).  To use them just add parameters to your delegate declaration and a create a constructor on your implementation type that matches.  You can still have dependencies that are resolved by the container in the constructor, for example:

public delegate IMyClassCreatedByFactory FactoryMethodName(String param1);  
public interface IMyClassCreatedByFactory
{ }  
public class MyClassCreatedByFactory
{
    public MyClassCreatedByFactory(IMyClass myClass, String param)
    { }
}  
public class FactoryConsumer : IFactoryConsumer
{
    FactoryMethodName _Factory;
    public FactoryConsumer(FactoryMethodName factory)
    { _Factory = factory; }  
    public void DoWork()
    {
        IMyClassCreatedByFactory c = _Factory("OCInject filling a gap that doesn't exist");
    }
}  
public class MyApp
{
    public void Run()
    {
        IClassFactory factory = new ClassFactory();  
        factory.RegisterType<IMyClass, MyClass>();
        factory.RegisterType<IFactoryConsumer, FactoryConsumer>();
        factory.RegisterType<IMyClassCreatedByFactory, MyClassCreatedByFactory>()
            .WithFactory<FactoryMethodName>();  
        IFactoryConsumer myClass = factory.ManufactureType<IFactoryConsumer>();
        myClass.DoWork();
    }
}

Where to Get it From and Further Examples

You can download it from BitBucket at http://bitbucket.org/humblecoder/ocinje ct/.  I don’t have any documentation at the moment but you can look at the DirLinker source and the unit tests for OCInject for more examples.

Enjoy and I hope someone finds it useful :)

Comments