Funq IoC 容器是否支持解析类型的所有注册?类似于以下任何一种:
IEnumerable<IFoo> foos = container.Resolve<IEnumerable<IFoo>>();
IEnumerable<IFoo> foos = container.ResolveAll<IFoo>();
Funq IoC 容器是否支持解析类型的所有注册?类似于以下任何一种:
IEnumerable<IFoo> foos = container.Resolve<IEnumerable<IFoo>>();
IEnumerable<IFoo> foos = container.ResolveAll<IFoo>();
Funq 没有ResolveAll
方法,但您可以简单地注册IEnumerable<IFoo>
并解决它,Resolve<IEnumerable<IFoo>>()
就像您在问题中显示的那样。
然而,一般来说,最好不要向容器请求集合,而是使用组合。这样,您可以简单地将 anIFoo
作为依赖项注入,而不是强制该依赖项的使用者迭代列表。相反,您嵌入了循环IFoo
组合内实例列表的代码。当必须对项目的迭代方式进行更改时,这可以使您的代码保持干燥,并且不会强迫您通过(可能的)散布在整个应用程序中的数十条语句。或者让我换一种说法:知道如何迭代所有sforeach (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;
}
void IFoo.FooThatThing(IBar bar)
{
foreach (var foo in this.foos)
{
foo.FooThatThing(bar);
}
}
}
IEnumerable<IFoo>
您可以将 a注册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
,我们可以在其中注入一些 lambda,而不是在构造函数中注入一些 s:
container.Register<IFoo>(c => new CompositeFoo(
() => c.Resolve<Foo1>(),
() => c.Resolve<Foo2>(),
() => c.Resolve<Foo3>()));
这将确保每次调用CompositeFoo
's时FooThatThing
都会向容器查询新IFoo
实例。这允许FooThatThing
被同一个消费者多次调用,甚至允许CompositeFoo
注册为单例。
这个建议一般适用于所有容器和依赖注入,并不特定于 Funq 的使用。
对于那些想要反模式的人,仅仅因为你可能不想实现工厂模式,这里是我基于上一个 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);
}
}
}
}