Ответ 1
В Funq нет метода ResolveAll
, но вы можете просто зарегистрировать IEnumerable<IFoo>
и разрешить его с помощью Resolve<IEnumerable<IFoo>>()
как показано в вашем вопросе.
В целом, однако, лучше не запрашивать контейнер для коллекций, а вместо этого использовать композиты. Таким образом, вы можете просто внедрить IFoo
в качестве зависимости, вместо того, чтобы заставлять потребителей этой зависимости повторять список. Вместо этого вы встраиваете код, который зацикливает список экземпляров IFoo
внутри композита. Это делает ваш код СУХИМЫМ и не вынуждает вас проходить через (возможные) десятки операторов foreach (var foo in foos)
разбросанных по всему приложению, когда необходимо внести изменения в способ итерации элементов. Или позвольте мне выразить это иначе: потребитель не обязан знать, как перебирать все IFoo
.
Вот пример IFoo
Composite:
// A composite is something that implements an interface
// (in this case IFoo) and wraps a list of items of that
// same interface.
public class FooComposite : IFoo
{
private readonly IEnumerable<IFoo> foos;
public FooComposite(params IFoo[] foos)
{
this.foos = foos;
}
void IFoo.FooThatThing(IBar bar)
{
foreach (var foo in this.foos)
{
foo.FooThatThing(bar);
}
}
}
Вместо регистрации IEnumerable<IFoo>
вы можете зарегистрировать CompositeFoo
как IFoo
:
container.Register<IFoo>(c => new CompositeFoo(
new Foo1(), new Foo2(), new Foo3()));
Теперь вы можете позволить контейнеру внедрить этот CompositeFoo
в потребителей, которые принимают аргумент IFoo
, что заставляет их не знать, что они на самом деле имеют дело со списком элементов IFoo
.
ОБНОВЛЕНИЕ:
Используя этот составной шаблон, вы можете легко управлять временем жизни каждого элемента IFoo
. Это просто вопрос обратного вызова в контейнер. С Funq это выглядело бы так:
container.Register<IFoo>(c => new CompositeFoo(
c.Resolve<Foo1>(),
c.Resolve<Foo2>(),
c.Resolve<Foo3>()));
Таким образом, вы можете зарегистрировать Foo1
как синглтон и Foo2
как переходный, например. Однако, когда CompositeFoo
используется повторно, Foo2
самом деле не будет переходным, но это просто вопрос изменения CompositeFoo
и его регистрации для решения этой проблемы. Например, вы можете изменить свой CompositeFoo
на следующее:
public class FooComposite : IFoo
{
private readonly Func<IFoo>[] fooFactories;
public FooComposite(params Func<IFoo>[] fooFactories)
{
this.fooFactories = fooFactories;
}
void IFoo.FooThatThing(IBar bar)
{
foreach (var fooFactory in this.fooFactories)
{
var foo = fooFactory();
foo.FooThatThing(bar);
}
}
}
Теперь вместо того, чтобы вводить IFoo
в конструктор, мы можем IFoo
в него несколько IFoo
:
container.Register<IFoo>(c => new CompositeFoo(
() => c.Resolve<Foo1>(),
() => c.Resolve<Foo2>(),
() => c.Resolve<Foo3>()));
Это гарантирует, что каждый раз, FooThatThing
вызывается CompositeFoo
FooThatThing
, контейнер запрашивается для новых экземпляров IFoo
. Это позволяет FooThatThing
вызываться несколько раз одним и тем же потребителем и даже позволяет регистрировать CompositeFoo
как singleton.
Этот совет относится ко всем контейнерам и внедрению зависимостей в целом и не относится к использованию Funq.