Humblecoder

Caution, this blog may be ironically named

OCInject Release 2

| Comments

When I originally released OCInject I omitted one important feature, lifestyle management.  This coupled with the release of a feature full TinyIOC has made me re-evaluate my position on not adding too many features to OCInject.  Release 2 of OCinject brings the following features:

  • Life style management – It’s possible to register types as singletons or instance
  • Func factories – OCInject from day one supported delegate factories, now you can use Func instead of typed delegates
  • Simplified Registrations – In the previous release of OCInject types are registered using TContract –> TImplemenation to enforce programming to interface.  It’s now possible to register with TContract as the concrete type with one call
  • Largest Resolvable ConstructorIn the previous release of OCInject it simply grabbed the first constructor it found.  It will now select the greediest constructor it can resolve.  It makes the assumption that any known types are resolvable, for performance reasons.
  • Unresolveable CallbackIt is now possible to supply a call back function if the container can’t resolve a type.
  • Child Container Support – OCInject can create child containers that call back to the parent for any unknown types. 

The latest stable version can be downloaded from Codeplex and all stableish development releases can be found at BitBucket.

#

Future Features

One major feature still missing from OCInject is named registrations.  This is because I personally dislike ‘magic strings’, with this in mind a planned future feature of OCInject is factory delegate registration only.  Also, auto generated factories from interfaces.  More to come on this in a future post.

Life Style Management

By default all types registered with the OCInject container are transient. You can register a type as singleton in two ways.  The first method is to use .AsSingleton() this will cause the object to be created the first time it is requested.  The second method is to use .AlwaysReturnObject(obj), this will return the instance you specified.   When using either method, if the type implements IDisposable it will be disposed when the container is.  Usage example:

ClassFactory container = new ClassFactory();  
//Normal Singleton
container.RegisterType<TestClass>()
           .AsSingleton();  
//Preconstructed Singleton
AnotherClass instanceOfAClass = new AnotherClass();  
container.RegisterType<TestClass>()
         .AlwaysReturnObject(instanceOfAClass);

Func Factories

When resolving constructors if OCInject discovers a Func where T is a registered type, it will pass in a func to create the type.  This uses the standard container resolve, so if T is a singleton you will always get the same instance when the factory is called. Usage example:

class FuncConsumer
{
    public FuncConsumer(Func<TestClass> factory)
    {
    }
}  
ClassFactory container = new ClassFactory();  
container.RegisterType<FuncConsumer>();
container.RegisterType<TestClass>();  
//Successfully created with the ability to create TestClass
FuncConsumer f = container.ManufactureType<FuncConsumer>();

Simplified Registrations

Registrations no longer require the separation of contract and implement so just an implementation can be registered.  Usage example:

ClassFactory container = new ClassFactory();  
container.RegisterType<TestClass>();  
var t = container.ManufactureType<TestClass>();

Largest Resolvable Constructor

This is quite a complicated area that is worthy of a blog post itself but OCInject’s behaviour has changed.  When creating a type the constructors are ordered so the largest, in terms of parameters, is first.  It then looks at each parameter and to see if it can resolve it, first by checking ‘resolve time args’ (values passed in when the resolve is requested, normally from generated factories) then by seeing if the type is a registered contract within the container.   It does not check if the type can be created just that it knows about it, if it’s registered it assumes it can be created.

The first completely resolvable constructor will be used to construct the type.

Unresolveable Callback

If the container is unable to resolve the type you can now register a function that is called before the container throws an exception.  To do this you need register a Func<Object, Type> with the CallToResolve propriety.  Returning null will cause the container to throw an exception.  Usage example:

ClassFactory container = new ClassFactory();  
container.CallToResolve = (type) => { return new TestClass(); };  
ITestClass manufacturedType = factory.ManufactureType<ITestClass>();

Child Container Support

Calling CreateChildContainer() will return a new ClassFactory object with no registrations but a link back to the parent.  If a type is not known to the child it will ask the parent to fulfil the request.  Any registrations with the child will not effect the parent and singletons registered with the child will be disposed when it is. Usage example:

ClassFactory container = new ClassFactory();
ClassFactory child = factory.CreateChildContainer();

Comments