-
Notifications
You must be signed in to change notification settings - Fork 235
Resolution constructor and property injection
Alex Maris edited this page Jan 26, 2016
·
3 revisions
// Basic named and unnamed resolution
var instance = container.Resolve<MyConcreteType>(); // Unnamed
instance = container.Resolve<MyConcreteType>("Name"); // Named
// By default we try and resolve every concrete type,
// whether they are registered or not, but we don't "fallback"
// to an unnamed registration if resolving a named one.
//
// We can easily change that behaviour though.
container.Resolve<MyConcreteType>(
new ResolveOptions() {UnregisteredResolutionAction = UnregisteredResolutionActions.Fail});
container.Resolve<MyConcreteType>("Name",
new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.AttemptUnnamedResolution });
// We can pass parameters using name/value pairs.
// By default the "greediest" constructor is used if possible,
// but we will fall all the way back to a default constructor if
// necessary to construct the type.
container.Resolve<MyConcreteType>(new NamedParameterOverloads() { { "property1", 12 }, { "property2", "Testing" } });
// We also have the same overloads on CanResolve
// to determine if resolution is possible
container.CanResolve<MyConcreteType>(
new ResolveOptions() { UnregisteredResolutionAction = UnregisteredResolutionActions.Fail });
container.CanResolve<MyConcreteType>("Name",
new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.AttemptUnnamedResolution });
container.CanResolve<MyConcreteType>(new NamedParameterOverloads() { { "property1", 12 }, { "property2", "Testing" } });
// And also for TryResolve, which will resolve if possible
// and return a boolean to indicate whether resolution completed
var resolved = container.TryResolve<MyConcreteType>("MyName", out resolvedType); // resolved is true if resolution was possible
// Resolve all resolves all registrations for a type, named or otherwise
// as IEnumerable<ResolveType>
container.Resolve<IMyInterface, MyType1>("MyType1"); // named registration
container.Resolve<IMyInterface, MyType2>("MyType2"); // 2nd named registration
IEnumerable<IMyInterface> myResolvedTypes = container.ResolveAll<IMyInterface>(); // Returns both registrations
// By default we will use the "greediest" constructor
// if we can..
public Constructors(ITestInterface1 dependency, string value1, int value2)
{
}
// .. but we will fallback if we can't - rather than
// throwing a resolution exception.
public Constructors(ITestInterface1 dependency)
{
}
// For types that are expensive to construct and may not
// always be needed we provide automatic lazy factories
// by putting Func<T> in the constructor
public Constructors(Func<MyExpensiveObject> expensiveObjectFactory)
{
var instance = expensiveObjectFactory.Invoke();
}
// We also allow lazy factories that specify a named registration
// to resolve using Func<String, T>:
public Constructors(Func<String, MyExpensiveObject> expensiveObjectFactory)
{
var instance = expensiveObjectFactory.Invoke("MyNamedRegistration");
}
// And we also allow you to specify named parameter overloads to lazy factories
// using Func<String, IDictionary<string, object>, T>:
public Constructors(Func<string, IDictionary<String, object>, TestClassWithParameters> factory)
{
_Factory = factory;
Prop1 = _Factory.Invoke("", new Dictionary<String, object> { { "stringProperty", "Testing" }, { "intProperty", 22 } });
}
// If constructor injection isn't possible/preferable we can also
// use property injection.
//
// Any public read/write property that we can resolve, that isn't
// already set to a value, is resolved by the container:
class TestClassPropertyDependencies
{
public ITestInterface Property1 { get; set; } // Will be set if we can resolve and isn't already set
public ITestInterface2 Property2 { get; set; } // Will be set if we can resolve and isn't already set
public int Property3 { get; set; } // Will be ignored
public string Property4 { get; set; } // Will be ignored
public TestClassDefaultCtor ConcreteProperty { get; set; } // Will be set if we can resolve and isn't already set
public ITestInterface ReadOnlyProperty { get; private set; } // Will be ignored
public ITestInterface2 WriteOnlyProperty { internal get; set; } // Will be ignored (no way to know if it's already set)
}
// -- SNIP -- //
var input = new TestClassPropertyDependencies();
container.BuildUp(input); // Properties are now set
// If we need to control scope or lifetime of particular
// registrations we can use child containers.
//
// We can get a child container from any container instance
var child = container.GetChildContainer();
// A child container will "bubble up" resolve requests if it can't resolve
// a type itself
container.Register<ITestInterface, TestClassDefaultCtor>();
var result = child.Resolve<ITestInterface>(); // Will resolve with the parent container
// If a type is registered with the child container it will resolve that
// instead of the same type registered with the parent:
container.Register<ITestInterface>(parentInstance);
child.Register<ITestInterface>(childInstance);
child.Resolve<ITestInterface>(); // Will return "childInstance"
// We can let the child container go out of scope because the
// parent holds no reference to it. Or we can Dipose() it which
// will DISPOSE ALL INSTANCES/SINGLETONS REGISTERED WITH IT if they
// support IDisposable:
child.Dispose(); // Disposes container and all disposable instances/singletons