11

Funq IoC 容器是否支持解析类型的所有注册?类似于以下任何一种:

IEnumerable<IFoo> foos = container.Resolve<IEnumerable<IFoo>>();
IEnumerable<IFoo> foos = container.ResolveAll<IFoo>();
4

2 回答 2

9

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注册CompositeFooIFoo

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 的使用。

于 2012-01-12T10:27:42.973 回答
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);
            }
        }
    }  
}
于 2016-06-22T13:25:01.943 回答