Что это значит в Prism / Unity: Container.Resolve <ShellPresenter>() - PullRequest
17 голосов
/ 11 марта 2009

(из файла StockTraderRIBootstrapper.cs в примере приложения Prism V2 StockTrader)

Какая разница между:

ShellPresenter presenter = new ShellPresenter();

и это:

ShellPresenter presenter = Container.Resolve<ShellPresenter>();
  • Я понимаю, что во втором примере контейнер обрабатывается как фабрика, подойдя к нему со словами: "Мне нужен экземпляр объекта типа ShellPresenter".
  • Но что, если, например, Мне нужно отправить параметры, что будет эквивалентно «новый ShellPresenter (1, true)» и т. Д .?
  • И поскольку контейнеру нужно рассказать о ShellPresenter, я ожидал найти где-нибудь в проекте место, где класс ShellPresenter будет зарегистрирован в контейнере, например, Я ожидал

как то так:

Container.RegisterType<IShellPresenter, ShellPresenter>();

но нигде не нашел. Так как же контейнер узнает об этих типах, чтобы он мог их разрешить? Я перестроил это в своем собственном проекте и получаю ошибку «Разрешение сбоя зависимости» , где мне тогда регистрировать эту зависимость?

Любое направление / обсуждение здесь будет полезно.

Необъяснимый ответ:

Итак, в загрузчике, когда я регистрирую сам Shell:

protected override void ConfigureContainer()
{
    Container.RegisterType<IShellView, Shell>();
    base.ConfigureContainer();
}

тогда Контейнер может разрешить тип ShellPresenter. Так как же регистрируется тип ShellPresenter при регистрации типа Shell ?

Удивительный ответ:

Хорошо, получается, что вам не нужно регистрировать тип, который вы пытаетесь разрешить, но вам нужно регистрировать типы параметров (интерфейса), передаваемые в конструктор типа, который вы пытаетесь разрешить , т. е. поскольку я внедряю интерфейс IShellView в конструктор моего ShellPresenter, мне нужно было зарегистрировать тип IShellView, а не тип IShellPresenter:

public ShellPresenter(IShellView view) ...

Я проверил это, пытаясь определить тип Tester :

Tester tester = Container.Resolve<Tester>();

Пока я добавляю SomeClass в его конструктор:

public Tester(ISomeClass someClass)

Я получаю неразрешенные ошибки зависимости, пока не регистрируюсь SomeClass в контейнере:

Container.RegisterType<ISomeClass, SomeClass>();

Тогда это работает. Это так же удивительно, как и образовательно. Нужно погрузиться. Я собираюсь пойти выпить кофе и немного подумать об этом.

Если кто-нибудь может уточнить, почему это так, это было бы очень признательно.

Ответы [ 4 ]

10 голосов
/ 21 апреля 2009

Если вы попытаетесь разрешить конкретный класс и не зарегистрируете экземпляр или подкласс для его удовлетворения, то Unity создаст для вас экземпляр конкретного класса, разрешив все имеющиеся у него зависимости.

Таким образом, когда вы запрашиваете ShellPresenter и не регистрируете его, Unity просто создает для вас ShellPresenter с ShellView в качестве параметра.

5 голосов
/ 11 марта 2009

Вы понимаете основы.

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

Смысл контейнеров DI заключается в том, что вы можете настроить их для изменения типа, который разрешается для определенного интерфейса, без перекомпиляции программного обеспечения. Пример кода, который вы предоставили для настройки провайдера, нельзя изменить во время выполнения. Вот почему большинство инжекторов зависимостей позволяют вам настраивать их в app.config / web.config / некотором другом внешнем файле конфигурации. Таким образом, вы можете перенастроить свое приложение для внедрения другого типа без перекомпиляции, что является истинной силой DI-фреймворков, таких как Unity.

1 голос
/ 11 марта 2009

В Unity действительно существует набор методов Container.RegisterType<TFrom, TTo>(), который регистрирует типы во время выполнения. Вероятно, более распространенным является использование файла конфигурации XML, но любой из них работает.

Интересно, что в Unity нет метода Container.Resolve<T>(params object[] parameters) -типа для разрешения типа с конкретными значениями параметров конструктора. Unity построен поверх ObjectBuilder, который является библиотекой команды P & P для создания объектов и соединения (IIRC изначально был написан для ObjectSpaces, но в настоящее время значительно улучшен). ObjectBuilder дает вам возможность вводить зависимости различными способами, в том числе через конструктор, так что вы можете сказать, например, что вы передадите новый экземпляр типа, от которого он зависит, в конструктор разрешенного типа; но этот тип также должен быть зарегистрирован. Вы также можете передавать экземпляры зарегистрированных типов (зарегистрированный экземпляр / singleton и т. Д.). Но AFAICS нет способа просто дать ему значение для передачи.

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

Я не могу говорить за Виндзор, StructureMap или другие, которые могут позволить вам сделать это. Я даже не могу категорически сказать, что у Unity нет никакого способа сделать это, поскольку я достаточно новичок в этом, но IIRC Крис Таварес - который в основном строил Unity - время от времени зависает здесь, так что, возможно, он заскочит и ответьте на это: -)

1 голос
/ 11 марта 2009

Ну, я не могу ответить за Untiy, но для Castle Windsor регистрация может быть в файле app.config / web.config. Также есть возможность добавить параметры в конфиг xml.

Это позволяет вам изменять реализацию и конфигурацию объекта без необходимости перекомпилировать ваше приложение.

...