A minimal IoC (Inversion of Control) container.
- .NET Standard 2.0 library
- automatic and/or explicit type registration
- public and internal constructor injection
- injection of instances, factories and collections
- transient and singleton lifestyles
- captive and recursive dependency detection
- dependencies: none
public class Container : IDisposable
{
public Container(...);
public Container RegisterTransient<T>();
public Container RegisterSingleton<T>();
public Container RegisterInstance(t);
public Container RegisterFactory(() => t);
public T Resolve<T>();
public string ToString();
public void Dispose();
}
using MinimalContainer;
public interface IFoo {}
public class Foo : IFoo {}
public class Example
{
public static void Main()
{
Container container = new Container();
container.RegisterTransient<IFoo, Foo>();
IFoo foo = container.Resolve<IFoo>();
...
container.RegisterSingleton<Foo>();
container.RegisterSingleton<IFoo, Foo>();
container.RegisterTransient<Foo>();
container.RegisterTransient<IFoo, Foo>();
container.RegisterInstance(new Foo());
container.RegisterInstance<IFoo>(new Foo());
container.RegisterFactory(() => new Foo());
container.RegisterFactory<IFoo>(() => new Foo());
T instance = container.Resolve<T>();
T instance = container.Resolve(typeof(T));
IList<T> instances = container.Resolve<IList<T>>();
A list of instances of registered types which are assignable to T
is returned.
Func<T> factory = container.Resolve<Func<T>>();
T instance = factory();
The container can create instances of types using public and internal constructors. In case a type has more than one constructor, decorate the constructor to be used with the 'ContainerConstructor' attribute. Otherwise, the constructor with the smallest number of arguments is selected.
public class Foo
{
public Foo() {}
[ContainerConstructor]
public Foo(IBar bar) {}
}
public class T {}
Container container = new Container(DefaultLifestyle.Singleton);
T instance = container.Resolve<T>();
To enable automatic registration, set the default lifestyle to singleton or transient when constructing the container. Note that the container will always register the dependencies of singleton instances as singletons. If automatic type resolution requires scanning assemblies other than the assembly where the container is created, include references to those assemblies in the container's constructor.
Foo1 foo1 = new Container()
.RegisterSingleton<Foo1>()
.RegisterTransient<Foo2>()
.RegisterInstance(new Foo3())
.RegisterFactory(() => new Foo4())
.Resolve<Foo1>();
using MinimalContainer;
internal interface IFoo {}
internal interface IBar {}
internal class Foo : IFoo {}
internal class Bar : IBar {}
internal class Root
{
private readonly IFoo foo;
private readonly Func<IBar> barFactory;
internal Root(IFoo foo, Func<IBar> barFactory)
{
this.foo = foo;
this.barFactory = barFactory;
}
private void StartApplication()
{
//...
}
public static void Main()
{
new Container(DefaultLifestyle.Singleton)
.Resolve<Root>()
.StartApplication();
}
}
The complete object graph is created by resolving the compositional root.
Action<string> log;
Container container = new Container(Log: log);
container.ToString();
container.Dispose();
Disposing the container disposes any registered disposable singletons.