Виндзор: как настроить контейнер, когда задействованы зависимости времени выполнения - PullRequest
1 голос
/ 22 января 2012

У меня есть это (вымышленное) настольное приложение, которое позволяет менеджерам проектов искать незанятых разработчиков и назначать задач . Модель:

interface IDeveloperFactory
{
   IDeveloper CreateDeveloper(string name);
}

interface IDeveloper 
{
    void WriteCode();
    void WriteUnitTest();
}

interface ITask
{
    void Complete();
}

class Developer : IDeveloper
{
   public Developer(string name) { ... }

   public void WriteCode()
   {
       Console.WriteLine("Developer {0} is writing code... done", name);
   }
   public void WriteUnitTest()
   {
       Console.WriteLine("Developer {0} is writing unit test... done", name);
   }
}

class WriteCodeTask : ITask
{
   public Task(Lazy<IDeveloper> lazyDeveloper) { ... }

   public void Complete()
   {
       var dev = lazyDeveloper.Value;
       dev.WriteCode();
   }
}

Developer имеет зависимость времени выполнения, поэтому я буду использовать DeveloperFooFactory (который настроен как типизированная фабрика) для получения IDeveloper. Пока используется IDeveloper, мне также нужны ITask, которые используют экземпляр разработчика, и моя работа была бы намного проще, если бы я мог просто попросить контейнер разрешить их:

var developerFactory = container.Resolve<IDeveloperFactory>();
var dev1 = developerFactory.CreateDeveloper("dev 1");
var task1 = container.Resolve<ITask>();
task1.Complete(); // uses dev1
var task2 = container.Resolve<ITask>();
task2.Complete(); // uses dev1
container.Release(dev1); // also releases task1 and task2

var dev2 = developerFactory.CreateDeveloper("dev 2");
var task3 = container.Resolve<ITask>();
task3.Complete(); // uses dev2
// task1, task2 and task3 are always different instances

Вопросы:

  1. Как я могу настроить контейнер для достижения этого? (Я намерен использовать версию 3.0)
  2. В идеале я бы не стал выпускать dev1 до создания dev2 (например, создавать dev одновременно в разных потоках), но мне все еще нужен контейнер для правильного разрешения ITask ... Мне нужно использовать дочерние контейнеры для этого, или, может быть, новый метод BeginScope в 3.0?
  3. Также возможно, что разработчик может обрабатывать несколько задач одновременно в разных потоках. Поэтому, когда мне нужна задача, я просто просил контейнер разрешить ее и использовать экземпляр «contextual developer» ... но как?

Я знаю, что могло бы быть проще, если бы не круговая зависимость. Однако кажется, что модель, реальная, я имею в виду, более естественна ...

1 Ответ

0 голосов
/ 24 января 2012

Понял, в конце концов ... не выглядит сложно, но я действительно новичок в Виндзоре.

Регистрация контейнера:

container.AddFacility<TypedFactoryFacility>();
container.Register(
    Component.For<IDeveloperFactory>().AsFactory(),
    Component.For<IDeveloper>().ImplementedBy<Developer>().LifestyleScoped(),
    Component.For<ITask>().ImplementedBy<WriteCodeTask>().LifestyleTransient(),
    Component.For<Lazy<IDeveloper>>().LifestyleTransient() // i don't use 4.0 so this is my own implementation of Lazy<> which depends on a Func<> on ctor
);

Тестовый код:

var developerFactory = container.Resolve<IDeveloperFactory>();
using (container.BeginScope())
{
    var developer = developerFactory.Create("John"); // this creates a new Developer and caches it in the current scope
    var task1 = container.Resolve<ITask>();
    var task2 = container.Resolve<ITask>();
    Assert.Same(task1.Developer, task2.Developer);
    Assert.Equal("John", task1.Developer.Name);

    task1.Complete();
    task2.Complete();
    container.Release(task1);
    container.Release(task2);
}

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

Моя другая просьба была о том, чтобы это работало в разных потоках.Это тоже нормально, потому что если код using (container.BeginScope()) { ... } выполняется в потоке, то контейнер создает и кэширует другой экземпляр разработчика для потока.Также я могу запустить дочерние потоки для решения задач и все равно получу правильный контекстный экземпляр разработчика.

...