Funq поддерживает ResolveAll? - PullRequest
11 голосов
/ 12 января 2012

Поддерживает ли контейнер Funq IoC разрешение всех регистраций для типа?Примерно так:

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

Ответы [ 2 ]

9 голосов
/ 12 января 2012

Funq не имеет метода ResolveAll, но вы можете просто зарегистрировать IEnumerable<IFoo> и разрешить его с помощью Resolve<IEnumerable<IFoo>>(), как показано в вашем вопросе.

В целом, однако, лучше не для запроса контейнера для коллекций, но вместо этого используйте composites .Таким образом, вы можете просто внедрить IFoo в качестве зависимости, вместо того, чтобы заставлять потребителей этой зависимости повторять список.Вместо этого вы встраиваете код, который зацикливает список IFoo экземпляров внутри композита.Это сохраняет ваш код DRY и не вынуждает вас проходить (возможные) десятки foreach (var foo in foos) операторов, разбросанных по всему приложению, когда необходимо внести изменения в способ итерации элементов.Или позвольте мне выразить это иначе: потребитель не обязан знать, как перебирать все IFoo s.

Вот пример 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 1044 * на самом деле не будет кратковременным, но это просто вопрос изменения 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 с, мы можем вставить в него несколько лямбд:

container.Register<IFoo>(c => new CompositeFoo(
    () => c.Resolve<Foo1>(),
    () => c.Resolve<Foo2>(),
    () => c.Resolve<Foo3>()));

Это гарантирует, что при каждом вызове CompositeFoo FooThatThing контейнер запрашивается для новых IFoo экземпляров.Это позволяет многократному вызову FooThatThing одним и тем же потребителем и даже позволяет регистрировать CompositeFoo как singleton.

Этот совет применим для всех контейнеров и внедрения зависимостей в целом и не относится киспользование Funq.

0 голосов
/ 22 июня 2016

Для тех из вас, кому нужен анти-шаблон, просто потому, что вы, возможно, не захотите реализовать фабричный шаблон, вот моя версия, основанная на последних 3.9.71.

Единственным недостатком является то, что он добавляетнемного больше памяти, и вы должны зарегистрировать сервисы через registerOneOfMany ().вы можете изменить пакет для списка с блокировкой (для более быстрого чтения) и переключиться на значение по умолчанию для servicstack: 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);
            }
        }
    }  
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...