I don’t actually need field and property injection from a dependency injection framework, do you?
And are XML configurations really required? Isn’t a small, tiny constructor injector sufficient?
For me, it must support
and it should be thread-safe.
Yesterday I’ve taken a look at StructureMap and Autofac, but both frameworks confused me a lot and I had a hard time finding out how they actually behave and if they support my needs. So, I decided to write my own, and here is it on google code:
In Konstruktor, there are two concepts, the Builder and the Scope:
To get started, a builder needs to instantiated, and then rules are added. When the set up of the builder is finished, a scope is generated and objects can be resolved (all the Examples are also available in the Konstructor.Test project):
sealed class A{public void printHelloWorld(){Console.WriteLine("Hello World");}}sealed class B{public readonly A A;public B(A a){A = a;}}[Test]public static void myFirstKonstrukt(){var b = new Builder();using (var s = b.beginScope()){var bInstance = s.resolve<B>();bInstance.A.printHelloWorld();}}
Here, an instance of A is automatically created and injected in B.
Of course, Konstruktor supports resolving instances by interfaces. To register an interface mapping (a concrete class that should be instantiated when the interface is requested), use Builder.iface<Interface, ConcreteType>():
interface IInterface{}sealed class Concrete : IInterface{}[Test]public static void mapInterface(){var b = new Builder();b.iface<IInterface, Concrete>();using (var s = b.beginScope()){var concrete = s.resolve<IInterface>();Assert.AreEqual(typeof(Concrete), concrete.GetType());}}
Builder.iface() also supports open generics, just specify the open types, for example to map all interfaces of IThreadSafe<T> to the concrete class ThreadSafe<T>, use
b.iface(typeof(IThreadSafe<>), typeof(ThreadSafe<>));
This works with arbitrary number of type arguments.
Konstruktor supports generating and injecting factory methods with optional parameterization, for example:
sealed class ClientInstance{public readonly Server Server;public ClientInstance(Server server){Server = server;}}sealed class Server{readonly Func<ClientInstance> _instanceCreator;public Server(Func<ClientInstance> instanceCreator){_instanceCreator = instanceCreator;}public ClientInstance createClient(){return _instanceCreator();}}[Test]public static void serverFunc(){var b = new Builder();using (var s = b.beginScope()){var server = s.resolve<Server>();var client1 = server.createClient();var client2 = server.createClient();Assert.AreNotSame(client1, client2);Assert.AreSame(client1.Server, server);Assert.AreSame(client2.Server, server);}}
The interesting application here is that Server is now able to create any number of client instances but the original Server instance can also injected into the clients.
For the generated Clients (for each Func<> call), Konstruktor creates a new scope.
Func-injection also works with one parameter. The parameter argument will be stored in the nested scope.
Some notable specialities and implementation details:
And some more features not mentioned:
Check out the source, or just browse it, license is the New BSD license, have fun.