Использование дочерних контейнеров Castle Windsor для разрешения типа с конкретным экземпляром - PullRequest
3 голосов
/ 08 ноября 2011

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

Возможно, какой-то код объяснит, что язначит.

У меня есть Func, который действует как фабрика Func<IReportCategory, IReportCategoryViewModel> - я даю ему реализацию IReportCategory, и он возвращает новый экземпляр IReportCategoryViewModel.(IReportCategoryViewModel зависит от IReportCategory).

Это зарегистрировано в Castle Windsor следующим образом:

        container.Register(
            Component.For<Func<IReportCategory, IReportCategoryViewModel>>().Instance(
                category => ResolveCategoryViewModelFactory(container, category)));

Где ResolveCategoryViewModelFactory реализовано следующим образом:

    private CategoryViewModel ResolveCategoryViewModelFactory(IWindsorContainer container, IReportCategory category)
    {
        using (IWindsorContainer childContainer = new WindsorContainer())
        {
            childContainer.Register(Component.For<IReportCategory>().Instance(category));
            container.AddChildContainer(childContainer);

            return childContainer.Resolve<IReportCategoryViewModel>();
        }
    }

Достигнутый выше метод достигает разрешения IReportCategoryViewModel, внедряющего конкретный экземпляр IReportCategory в качестве зависимости.Если IReportCategoryViewModel имеет другие зависимости, которые должны быть удовлетворены, контейнер автоматически вводит их.

Впоследствии я могу использовать Func следующим образом:

public class Test
{
    private readonly Func<IReportCategory, IReportCategoryViewModel> factory;

    public Test(Func<IReportCategory, IReportCategoryViewModel> factory)
    {
        this.factory = factory;
    }

    public void ResolveTest()
    {
        // Create a category (note: this would probably be resolved from the container in some way)
        IReportCategory category = new ReportCategory();

        // Call into the factory to resolve the view model
        IReportCategoryViewModel vm = factory(category);
    }
    ...

Вопрос: Это похоже на подходящую вещь?Судя по моему впечатлению, в Castle Windsor не рекомендуются дочерние контейнеры - есть ли другой способ достижения того же результата?

Спасибо за вашу помощь.

Ответы [ 2 ]

4 голосов
/ 10 ноября 2011

Следуя совету Кшиштофа по использованию Typed Factories, вот как я реализовал вышеуказанную функциональность.Это гораздо проще, чем использование дочерних контейнеров!

Во-первых, создайте фабричный интерфейс, который определяет сигнатуру фабричного метода:

public interface ICategoryViewModelFactory
{
    CategoryViewModel Create(ReportCategory category);
} 

Далее, убедитесь, что TypedFactoryFacility включен вконтейнер:

container.AddFacility<TypedFactoryFacility>();

Наконец, зарегистрируйте интерфейс фабрики с контейнером:

container.Register(
    Component.For<ICategoryViewModelFactory>()
        .AsFactory());

Теперь вы можете добавить ICategoryViewModelFactory в ваши классы и вызвать метод Create() длясоздайте новый экземпляр CategoryViewModel:

public class SomeClass
{
    public SomeClass(ICategoryViewModelFactory categoryViewModelFactory)
    {
        // This would probably be resolved by the container (it's like this for the example)
        ReportCategory category = new ReportCategory();

        // Get Windsor to resolve the view model using the factory
        ReportCategoryViewModel vm = categoryViewModelFactory.Create(category);

        ....

Предупреждение: Имя параметра в методе фабрики должно соответствовать имени параметра конструктора объекта, создаваемого фабрикой.В приведенном выше примере фабричный интерфейс определяет метод:

CategoryViewModel Create(ReportCategory category)

Конструктор для CategoryViewModel также должен иметь параметр с именем "category":

public CategoryViewModel(ReportCategory category)

Это потому, чтоЗаводской метод эквивалентен следующему:

container.Resolve<CategoryViewModel>(new { category = paramPassedIntoFactoryMethod });
2 голосов
/ 10 ноября 2011

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

Если я правильно понимаю ваше объяснение, это похоже на работу для печатных фабрик .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...