-
-
Notifications
You must be signed in to change notification settings - Fork 72
Description
Pattern based resolution
Types of dependencies
While creating instances of classes, the container perform the following tasks:
- It calls constructor while providing required arguments
- Initializes required fields with values
- Initializes required properties
- Calls configured methods while supplying arguments
All these values used to initialize fields, properties, and parameters are called dependencies. Unity container recognizes three types of dependencies:
- Implicit dependencies
- Annotated dependencies
- Injected dependencies
Each of these types of dependencies could be a required or an optional dependency.
Implicit dependencies
Implicit dependencies are always parameters. Implicit dependencies are created when constructor or method is marked for injection but no specific information on how to inject parameters is provided. Consider the following example:
class SomeType
{
public string fild;
[InjectionConstructor]
public SomeType(object instance) { ... }
public long Property { get; set; }
[InjectionMethod]
public void SomeMethod(int value =12) { ... }
}Implicit dependencies are resolved as follows:
- If parameter has default value, the parameter is an optional dependency
- If parameter has no default, it is a required dependency
Optional dependencies
When resolved, optional dependencies do not cause resolution to fail in case the container can not fulfill the request. If value can not be resolved, the container returns default value.
Required dependencies
Inability to resolve required dependency causes whole request to fail. Required dependencies must be resolved in order to proceed further.
Annotated dependencies
Parameters, fields, and properties could be annotated with attributes to designate them for injection. In case of parameters, to be injected, the method or constructor must be annotated for injection as well. Same as implicit dependencies, annotated dependencies could be required or optional:
class SomeType
{
[OptionalDependency]
public string fild;
[InjectionConstructor]
public SomeType([OptionalDependency] object instance) { ... }
[Dependency]
public long Property { get; set; }
[InjectionMethod]
public void SomeMethod([Dependency] int value =12) { ... }
}Optional dependencies
Annotated optional dependencies follow the same pattern as implicit and do not cause resolution to fail if value can not be resolved.
For parameters if default value is provided, the container will use it, if not, default(T) will be returned.
In case of fields or properties, when dependency can not be resolved, nothing is assigned. So, if field or property were assigned some initial value, the value will be preserved.
Required dependencies
Required dependencies are either resolved, or the whole request fails.
Ambiguous annotations
Annotating parameters with required dependency and providing default value creates conflicting annotation:
[Dependency]
public string fild = 22;
[InjectionMethod]
public void SomeMethod([Dependency] int value =12) In cases where annotation is contradicting default value, the annotation takes precedence and overrides optional dependency with required. So, when the dependency could not be resolved, the request fails even if default value is provided.
Injected dependencies
All these types above do not require type to be registered with the container. It will work on either registered or unregistered types.
Injected dependencies are require type to be registered. These dependencies are created when type is being registered by providing various InjectionMember instances corresponding to injected parameters, fields, and properties.
Dependencies configured with injection have highest priority and will override implicit or annotated dependencies.