I want to use IoD with a class that implements an interface and has constructors with parameters.
The interface:
public interface IUsefulClass
{
string InterestingInfo { get; set; }
string RelevantStuff { get; set; }
}
Two simple properties, nothing much to say about it.
The class:
public class UsefulClass : IUsefulClass
{
public string InterestingInfo { get; set; }
public string RelevantStuff { get; set; }
public UsefulClass()
{
}
public UsefulClass(string p_strInterestingInfo)
{
InterestingInfo = p_strInterestingInfo;
}
public UsefulClass (string p_strInterestingInfo, string p_strRelevantStuff)
{
InterestingInfo = p_strInterestingInfo;
RelevantStuff = p_strRelevantStuff;
}
}
It has several different constructors, each setting the properties in its own way.
The call from another class:
public void HereGoes()
{
IUnityContainer z_ucoContainer = new UnityContainer();
z_ucoContainer.RegisterType<IUsefulClass, UsefulClass>();
IUsefulClass z_objUsefulButEmpty = z_ucoContainer.Resolve<IUsefulClass>();
IUsefulClass z_objUsefulAndInteresting = z_ucoContainer.Resolve<IUsefulClass>(new ParameterOverride("p_strInterestingInfo", "This is interesting information"));
IUsefulClass z_objUsefulAndInterestingToo = z_ucoContainer.Resolve<IUsefulClass>(new ParameterOverride[] { new ParameterOverride("p_strInterestingInfo", "This is very interesting information") });
IUsefulClass z_objUsefulInterestingAndRelevant = z_ucoContainer.Resolve<IUsefulClass>(new ParameterOverride("p_strInterestingInfo", "This is quite interesting information"), new ParameterOverride("p_strRelevantStuff", "More relevant stuff here"));
IUsefulClass z_objUsefulInterestingAndRelevantAsWell = z_ucoContainer.Resolve<IUsefulClass>(new ParameterOverride[] { new ParameterOverride("p_strInterestingInfo", "This is possibly the most interesting information"), new ParameterOverride("p_strRelevantStuff", "Look for relevant stuff there") });
}
On testing and debugging, I find that all five variables have null
in both properties.
Debugging some more, it turns out that each Resolve()
calls the parameter-less constructor.
I tried removing said constructor (and the code line that sets z_objUsefulButEmpty
, naturally): I get a Unity.ResolutionFailedException with the message, "Resolution failed with error: Failed to select a constructor for RegMat_VM.Infrastructure.UsefulClass".
I've looked and looked (here and there among other places), but can't find what I've done wrong. How can I make it work right?
The solution is to call like this:
IUnityContainer z_ucoContainer = new UnityContainer();
z_ucoContainer.RegisterType<IUsefulClass, UsefulClass>();
z_ucoContainer.RegisterType<IUsefulClass, UsefulClass>("stringConstructor",new InjectionConstructor (typeof(string)));
z_ucoContainer.RegisterType<IUsefulClass, UsefulClass>("string2Constructor", new InjectionConstructor (typeof(string), typeof(string)));
IUsefulClass z_objUsefulButEmpty = z_ucoContainer.Resolve<IUsefulClass>();
IUsefulClass z_objUsefulAndInteresting = z_ucoContainer.Resolve<IUsefulClass>("stringConstructor",new ParameterOverride("p_strInterestingInfo", "This is interesting information"));
IUsefulClass z_objUsefulAndInterestingToo = z_ucoContainer.Resolve<IUsefulClass>("stringConstructor",new ParameterOverride[] { new ParameterOverride("p_strInterestingInfo", "This is very interesting information") });
IUsefulClass z_objUsefulInterestingAndRelevant = z_ucoContainer.Resolve<IUsefulClass>("string2Constructor",new ParameterOverride("p_strInterestingInfo", "This is quite interesting information"), new ParameterOverride("p_strRelevantStuff", "More relevant stuff here"));
IUsefulClass z_objUsefulInterestingAndRelevantAsWell = z_ucoContainer.Resolve<IUsefulClass>("string2Constructor",new ParameterOverride[] { new ParameterOverride("p_strInterestingInfo", "This is possibly the most interesting information"), new ParameterOverride("p_strRelevantStuff", "Look for relevant stuff there") });
This involves knowledge of construction injection.
When there are multiple constructors, you can use InjectionConstructorAttribute
to decorate the only constructor you need.
When you need to use multiple constructors
at the same time, you need to name them and use that name when parsing.
For a more general use of named constructors, see below:
using System;
using System.Collections.Generic;
using Unity;
using Unity.Injection;
using Unity.Resolution;
namespace ConsoleApp1 {
class Program {
static void Main (string[] args) {
IUnityContainer container = new UnityContainer();
container.RegisterType<IPeople, Swordsman>(new InjectionConstructor());//Unnamed default registration, the following default registration will overwrite the previous one
container.RegisterType<IPeople, Witch>("Witch");//Named registration
IPeople people=container.Resolve<IPeople>();//Resolve default objects
IPeople _witch =container.Resolve<IPeople>("Witch");//Specify the name resolution object
IEnumerable<IPeople> peoples=container.ResolveAll<IPeople>();//Get all registered named objects of IPeople in the container
people.ClassName = people.GetType().ToString();
_witch.ClassName = _witch.GetType().ToString();
var info1= people.ShowInfo();
var info2= _witch.ShowInfo();
foreach (var item in peoples)
{
item.ClassName = item.GetType().ToString();
Console.WriteLine(item.ShowInfo());
}
Console.WriteLine(info1);
Console.WriteLine(info2);
//Dealing with the case of multiple constructors:
container.RegisterType<IPeople, Swordsman>("SString",new InjectionConstructor(typeof(string)));
container.RegisterType<IPeople, Swordsman>("TString", new InjectionConstructor(typeof(string), typeof(string)));
var people2=container.Resolve<IPeople>("SString",new ParameterOverride("o" ,"hello"));
IPeople people3=container.Resolve<IPeople>("TString",new ParameterOverride ("o", "hello"),new ParameterOverride ("g", "world"));
Console.WriteLine(people2.ClassName);
Console.WriteLine(people3.ClassName + people3.ClassAge);
Console.ReadLine();
}
}
//People interface
public interface IPeople {
string ClassName {
get; set;
}
string ClassAge {
get; set;
}
string ShowInfo ();
}
//Witch
public class Witch : IPeople {
public string ClassName {
get; set;
}
public string ClassAge {
get; set;
}
public string ShowInfo () {
return string.Format("Witch:{0}", ClassName);
}
}
//Swordsman
public class Swordsman : IPeople {
public string ClassName {
get; set;
}
public string ClassAge {
get;set;
}
public string ShowInfo () {
return string.Format("Swordsman:{0}", ClassName);
}
public Swordsman (string o) {
ClassName = o;
}
//[InjectionConstructor]
public Swordsman () {
}
public Swordsman (string o, string g) {
ClassName = o;
ClassAge = g;
}
}
}
Output: