Funq IoC容器是否支持解析某类型的所有注册?像这两个中的任何一个:
IEnumerable<IFoo> foos = container.Resolve<IEnumerable<IFoo>>();
IEnumerable<IFoo> foos = container.ResolveAll<IFoo>();
答案 0 :(得分:8)
Funq没有ResolveAll
方法,但您只需注册一个IEnumerable<IFoo>
,然后在问题中显示Resolve<IEnumerable<IFoo>>()
即可解决此问题。
但一般情况下,最好不为容器请求集合,而是使用composites。这样,您可以简单地将IFoo
作为依赖项注入,而不是强制该依赖项的使用者迭代列表。相反,您嵌入了在复合内部循环IFoo
实例列表的代码。这样可以保留代码DRY,并且不会强制您浏览分散在整个应用程序中的(可能的)数十个foreach (var foo in foos)
语句,而必须按照项目的迭代方式进行更改。或者让我以另一种方式说:消费者有责任知道如何迭代所有IFoo
。
以下是IFoo
复合材料的示例:
// 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.ToArray();
}
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
元素的列表。 / p>
<强>更新强>:
使用此复合模式,您可以轻松控制每个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.ToArray();
}
void IFoo.FooThatThing(IBar bar)
{
foreach (var fooFactory in this.fooFactories)
{
var foo = fooFactory();
foo.FooThatThing(bar);
}
}
}
现在我们可以在构造函数中注入一些lambdas,而不是注入一些IFoo
:
container.Register<IFoo>(c => new CompositeFoo(
() => c.Resolve<Foo1>(),
() => c.Resolve<Foo2>(),
() => c.Resolve<Foo3>()));
这将确保每次调用CompositeFoo
FooThatThing
时,都会查询容器以查找新的IFoo
个实例。这允许同一个消费者多次调用FooThatThing
,甚至允许CompositeFoo
注册为单身。
此建议通常适用于所有容器和依赖注入,并不特定于Funq的使用。
答案 1 :(得分:0)
对于那些想要反模式的人,仅仅因为你可能不想实现工厂模式,这里是我的版本基于最后的3.9.71。
唯一的缺点是它增加了更多的内存,你必须通过registerOneOfMany()注册服务。您可能想要更改带有锁的列表的行李(用于更快的读取)并切换到servicstack funq的默认值:ReuseScope.Default
public static class FunqExtensions
{
private static readonly ConcurrentDictionary<Type,ConcurrentBag<string>> registrations = new ConcurrentDictionary<Type, ConcurrentBag<string>>();
public static void RegisterOneOfMany<TBase, TImplementation>(this Container container, string name = null, ReuseScope scope = ReuseScope.None) where TImplementation : TBase
{
if (name == null)
name = Guid.NewGuid().ToString();
var funq = Container.GenerateAutoWireFn<TImplementation>();
container.Register<TBase>(name, (c) => funq(c))
.ReusedWithin(scope);
registrations.GetOrAdd(typeof(TBase), type => new ConcurrentBag<string>()).Add(name);
}
public static IEnumerable<T> ResolveAll<T>(this Container container)
{
ConcurrentBag<string> result;
if (registrations.TryGetValue(typeof(T), out result))
{
var rator = result.GetEnumerator();
while (rator.MoveNext())
{
yield return container.ResolveNamed<T>(rator.Current);
}
}
}
}