Ninject: инъекция двух разных объектов одного типа - PullRequest
8 голосов
/ 23 февраля 2012

Если у меня есть класс, который имеет двойные зависимости одного и того же типа (нужны два разных экземпляра), если единственное различие между экземплярами - это более глубокая зависимость, то как лучше всего заставить Ninject выполнять DI и сохранять два графикаОтдельный?

Пример граф объекта:

foo → ClassA → ClassB
bar → ClassA → ClassB

Класс C конструктор:

public class C
{
    public C(ClassB foo, ClassB bar) { … }
}

Итак, как мне убедиться, что ClassB, инстанцированный с foo, поставляется как ClassB зависимость foo, а barbar?

Просто для некоторого фона у меня былонекоторые требования меняются, поэтому мне нужно заменить репозиторий только для записи (IAdd) на композитный репозиторий только для записи

public class CompositeWriteRepository<T> : IAdd<T>
{
    public CompositeWriteRepository(IAdd<T> foo, IAdd<T> bar, Func<T, bool> descriminator) { ... }
    public Add(T entity)
    {
        if (descriminator(entity)) {
            foo.Add(entity);
        } else {
            bar.Add(entity);
        }
    }        
}

С помощью насмешек, это было достаточно просто, я мог бы просто ввести, используя имена:

 kernel.Bind<IAdd<EntityType>>().To<fooRepository>().Named("foo");
 kernel.Bind<IAdd<EntityType>>().To<barRepository>().Named("bar");

 kernel.Bind<IAdd<EntityType>>().To<CompositeWriterRepository<EntityType>>()
    .WithConstructorArgument("foo", x => x.Kernel.Get<IAdd<EntityType>>("foo")
    .WithConstructorArgument("bar", x => x.Kernel.Get<IAdd<EntityType>>("bar");

Проблема возникает, когда я использую настоящие репозитории;foo и bar в конечном итоге записывают файлы, поэтому им нужны разные имена файлов.Поскольку они являются StreamWriter репозиториями, одна из их зависимостей фактически получает два разных имени файла.

string FileName → FileStreamWriterFactory → StreamRepository → CompositeRepository

Единственный способ, который я нашел до сих пор для конструирования, - это создать именованное FileNameс именем FileStreamWriterFactory, с именем StreamRepository × 2 (один раз для foo и один раз для bar).Это похоже на много работы, поэтому я надеюсь, что есть лучшее решение.

Я могу изменить архитектуру при необходимости, это было похоже на элегантный способ быстро добавить разделение записей, когдатребования изменились.Я понимаю, что все мои классы довольно специфичны, но я думаю, что в целом это поддержит одна ответственность, и в моем случае мы пишем несколько небольших приложений и имеем больше запросов, которые мы можем выполнить, так что это хороший способ получить много повторно используемого кода.В общем, мне просто нужно переконфигурировать для различных задач.

Решение
Remo Gloor должен получить кредит;Это, вероятно, лучшая практика.

На самом деле я создал новое расширение

public static bool WhenAnchester(this IRequest request, Func<IRequest, bool> conditions)
{
    var parentContext = request.ParentContext;
    if (parentContext == null) {
            return false;
    }

    return conditions(parentContext.Request) || 
        parentContext.Request.WhenAnchester(conditions);
} 

Это позволило мне легко контролировать, какой файл будет вставлен в какой репозиторий.

kernel.Bind<string>().ToConstant("Foo.txt")
    .When(x => x.Target.Name == "filepath" && 
              x.WhenAnchester(t => t.Target != null && t.Target.Name == "Dest1"));

kernel.Bind<string>().ToConstant("Bar.txt")
    .When(x => x.Target.Name == "filepath" &&
               x.WhenAnchester(t => t.Target != null && t.Target.Name == "Dest2"));

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

1 Ответ

4 голосов
/ 23 февраля 2012

Да, есть лучший способ

См. https://github.com/ninject/ninject/commit/60443badf4ef840531c93e9287b154a9bba337c2

Это 3.0, но IsAnyAnchestorNamed также можно использовать с 2.2 из условия Когда.

...