Ninject: инъекция двух разных объектов одного типа

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

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

foo → ClassA → ClassB
bar → ClassA → ClassB

Учебный класс C конструктор:

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

Итак, как мне убедиться, что ClassB созданный с foo поставляется как ClassB зависимостях foo, а также bar... bar?

Просто для некоторых пределов у меня изменились требования, поэтому мне нужно заменить репозиторий только для записи (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 ответ

Решение

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

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

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

Другие вопросы по тегам