I have Unity injection implemented on constructors. I have the follow:
interface IA
{
DoSomething();
}
class A : IA
{
private List<MyType> List;
public A(List<MyType> list)
{
this.List = list;
}
DoSomething()
{
// do something with this.List
}
}
interface IB
{
List<MyType> GetList();
}
class B : IB
{
public List<MyType> GetList() { }
}
class C
{
private A MyA;
public C(IB b)
{
this.MyA = new A(b.GetList());
}
public DoSomethingInA()
{
this.MyA.DoSomething();
}
}
I want to remove the "new A()" in constructor of class C and use injection of IA but I dont know how to register A of type IA receiving in constructor a property of an instance and not an instance itself.
I can't change implementation of A !! a List<> should be received in constructor.
Thanks in advance !
The constructor of class C
does too much; injector constructors should be simple. So instead of calling GetList
during construction of the object graph, postpone this till a later moment and just inject IB
in both A
and C
as follows:
class A : IA
{
private IB b;
public A(IB b) {
this.b = b;
}
DoSomething() {
var list = this.b.GetList();
// do something with this.List
}
}
class C
{
private IB b;
public C(IB b) {
this.b = b;
}
}
This simplifies your registration, your code, and allows you compose object graphs with confidence.
UPDATE
In case the type is out of your control, you should consider it 3rd party type. In general, you should be careful in letting such type be auto-wired by the container, since the people that maintain that type might add new constructors to that type, which might break your DI registration (more info here).
So instead of letting the container auto-wire that type, register a lambda expression that creates the instance of that 3rd party type. For instance:
container.Register<IA>(new InjectionFactory(c => new A(c.Resolve<IB>().GetList())));
Do note however, that in this case you're still doing too much during the building of the object graph, and (depending on what GetList
does under the covers) that might make it harder to verify the correctness of the graph.
So because you are working with a 3rd party type that depends on some runtime types during its construction, you might want to consider postponing the creation of that type. If you create a proxy class for IA
, you will be able to delay the creation of A
without the application to know anything about it. That proxy might look something like this:
class DelayedAProxy : IA
{
private readonly Lazy<IA> a;
public DelayedAProxy(Lazy<IA> a) {
this.a = a;
}
public DoSomething() {
this.a.Value.DoSomething();
}
}
And you can register it as follows:
container.Register<IA>(new InjectionFactory(c =>
{
var lazy = new Lazy<IA>(() => new A(c.Resolve<IB>().GetList()));
new DelayedAProxy(lazy);
}));
Here we don't register A
directly, but DelayedAProxy
instead and that proxy will only cause A
to be created when DoSomething
is executed for the first time, which will be after the complete object graph is created.
Alternatively, your proxy could also just depend on IB
and create the lazy internally. That would like this:
class DelayedAProxy : IA
{
private readonly Lazy<IA> a;
public DelayedAProxy(IB b) {
this.a = new Lazy<IA>(() => new A(b.GetList()));
}
public DoSomething() {
this.a.Value.DoSomething();
}
}
Advantage of this is that the registration of the DelayedAProxy
becomes much easier:
container.RegisterType<IA, DelayedAProxy>();
Although it looks like in this case the DelayedAProxy
constructor is doing again a lot, in fact it just creates the Lazy with the delegate. GetList
is only called after the construction of the proxy.