Reputation: 33
This question is about IoC in general, but I'm using Autofac, so an Autofac solution would be great.
So assume the following classes:
class A
{
IEnumerable<B> GetBs();
}
class B
{
// Some code
}
class C
{
readonly IEnumerable<B> bs;
C(IEnumerable<B> bs)
{
this.bs = bs;
}
}
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.Register<A>();
builder.Register<C>();
var container = builder.Build();
var c = container.Resolve<C>();
// do something with c
}
}
the above Main
will fail.
I've noticed that I can solve this by adding this line of code:
builder.Register(c => c.Resolve<A>().GetBs())
However, that doesn't feel right. Any other way to achieve this? Or design changes?
Upvotes: 3
Views: 1533
Reputation: 7126
Given your reply to the accepted answer, there might be another technique to use in Autofac. If the set of plugins is available during registration, you could register them as a collection.
Upvotes: 0
Reputation: 233125
As given, this class structure looks perfectly fine. You are properly using Constructor Injection and using the static structure of the classes to communicate invariants and relationships. On the level of information provided here, I think the only thing missing is a Guard Clause in the C constructor :)
On a conceptual level it's harder to answer whether or not this is a good design. That depends on context not provided here. Is B a Service or an Entity? What is the intended source of Bs?
As a general rule of thumb we should only inject Services, but handle Entities with Services (such as Repositories or Gateways or whatnot), so if B represents a Service it would be okay to inject it into C. If it represents an Entity, then it becomes suspect - unless C is also an Entity...
On another note you can ask about the canonical source of Bs. If A truly is meant to be the container of Bs, then the above solution is correct (and idiomatic Autofac code). If the Bs really have a different origin, resolving them through A may be a hack...
Upvotes: 3