Selecting Constructor
By Number of Parameters
Selecting constructor by number of parameters is the simplest form of selection. You could use this selection method if the constructor you invoking has unique number of parameters.
Type of Parameter as Contract Type
This method is useful when you are working on a Type that takes certain number of parameters but you don't care what these parameter types are.
Parameters
In a case like this you could use Resolve.Parameter()
to specify that you want a parameter at this position to be resolved. For example, consider the following Type:
public class SampleType
{
public SampleType(object arg) => Ctor = 1;
public SampleType(IService service, object arg) => Ctor = 2;
public SampleType(IService service, object arg, Type type) => Ctor = 3;
public int Ctor { get; } // Constructor called
}
It has several constructors with different number of parameters each. Normally, the container would try to run the most complex constructor, but if you want to invoke the one with just a single parameter you need to register it like this:
Container.RegisterType<SampleType>( Invoke.Constructor( Resolve.Parameter() ));
In this registration you configure the container to invoke a constructor that takes just one parameter. The parameter is resolved using a contract with a type of the parameter and no name.
Now if you resolve the type, the container will invoke that constructor and inject the parameter:
var instance = Container.Resolve<SampleType>();
// 1 == instance.Ctor
Generic Parameters
The same method as above, could be used to invoke constructors with generic parameters. Consider the following class:
public class SampleType<T>
{
public SampleType(T arg)
{
Ctor = 1;
Value = arg;
}
public SampleType([Dependency("one")]IService service, T arg)
{
Ctor = 2;
Service = service;
Value = arg;
}
public SampleType(IService service, T arg, object obj)
{
Ctor = 3;
Service = service;
Value = arg;
}
public int Ctor { get; } // Called Constructor
public IService Service { get; }// Service passed in
public T Value { get; } // Generic argument value
}
To configure the container to invoke the first constructor you would execute the same code with exception of how you pass in a type of the contract. Registration of an open generic requires a conventional method call:
Container.RegisterType(typeof(SampleType<>), Invoke.Constructor( Resolve.Parameter() ));
When resolved, the container will invoke the first constructor and inject it with created instance of Object
:
var instance = Container.Resolve<SampleType<object>>();
// 1 == instance.Ctor
Parameter dependencies with Contract Name
When configuring constructors with the method described above you should be mindful of parameter annotations and contract names these annotations might provide.
When implicitly injecting a parameter, the container will recognize all metadata the parameter is annotated with and will properly inject it with correct contract. When you add an InjectionMember to configure the parameter you override all these annotations.
If you look at the second constructor of SampleType<T>
you will notice that the first parameter is marked with Dependency attribute. Normally, when resolving that parameter, Unity will, if present, use Name of the Contract the attribute provides. But when you register it as in the following example, you will override that contract:
Container.RegisterType<IService, Service>()
.RegisterType<IService, ServiceOne>("one")
.RegisterType<IService, ServiceTwo>("two");
Container.RegisterType(typeof(SampleType<>),
Invoke.Constructor(
Resolve.Parameter(),
Resolve.Parameter()));
var instance = Container.Resolve<SampleType<object>>();
// 2 == instance.Ctor
// typeof(Service) == instance.Service.GetType()
When resolved, Unity will execute the constructor but instead of dependency with contract name one
it will use contract with no name.
If you need to, you could override contract name explicitly as in the following example:
Container.RegisterType(typeof(SampleType<>),
Invoke.Constructor(
Resolve.Parameter("two"),
Resolve.Parameter()));
var instance = Container.Resolve<SampleType<object>>();
// 2 == instance.Ctor
// typeof(ServiceTwo) == instance.Service.GetType()
If you'd like to preserve contracts from annotations, you need to use one of the following selection methods instead.