Как разрешить сбор с параметром фильтрации?

Может ли Castle Windsor разрешить коллекцию, отфильтрованную по строковому параметру?

interface IViewFactory
{
   IView[] GetAllViewsInRegion(string regionName);
}

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

Я пробовал делать это с помощью Castle's Typed Factory Facility, ComponentModel Construction Contributors и Handler Selectors, но я не могу понять, как сопоставить несколько типов со строкой таким образом, чтобы Castle мог получить доступ, или как расширить Castle до проверьте строку, когда она решит, какие типы попытаться разрешить и вернуть в контейнер.


person Joel V. Earnest-DeYoung    schedule 22.02.2012    source источник


Ответы (1)


Строковый выбор строго необходим? Можно ли вместо этого, чтобы все реализации IView в одной и той же «области» реализовали выделенный интерфейс, производный от IView? Затем вы можете использовать WindsorContainer.ResolveAll () (передав свой региональный IView как T) для разрешения реализаций для рассматриваемого региона (или вы можете использовать один из преобразователей коллекции для выполнения внедрения конструктора).

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

Обновление: поскольку мы подтвердили, что в этом случае необходим выбор по строке, лучшее решение, которое я вижу, - это просто проверить список обработчиков в ядре, удовлетворяющих службе IView, а затем отфильтровать исполнителей, где регион (определенный с помощью атрибута) соответствует тому, что мы хотим, а затем разрешите этих разработчиков. Это кажется немного хакерским, но если вы согласны с прямой ссылкой на контейнер в вашей реализации IViewFactory, это, похоже, работает нормально. Ниже приведен успешный тестовый пример, демонстрирующий решение.

    [Test]
    public void Test()
    {
        using (var factory = new ViewFactory())
        {

            var regionOneViews = factory.GetAllViewsInRegion("One");
            Assert.That(regionOneViews, Is.Not.Null);
            Assert.That(regionOneViews, Has.Length.EqualTo(2));
            Assert.That(regionOneViews, Has.Some.TypeOf<RegionOneA>());
            Assert.That(regionOneViews, Has.Some.TypeOf<RegionOneB>());

            var regionTwoViews = factory.GetAllViewsInRegion("Two");
            Assert.That(regionTwoViews, Is.Not.Null);
            Assert.That(regionTwoViews, Has.Length.EqualTo(1));
            Assert.That(regionTwoViews, Has.Some.TypeOf<RegionTwoA>());
        }
    }
}

public interface IViewFactory
{
    IView[] GetAllViewsInRegion(string regionName);
}

public class ViewFactory : IViewFactory, IDisposable
{
    private readonly WindsorContainer _container;

    public ViewFactory()
    {
        _container = new WindsorContainer();
        _container.Register(
            Component.For<IView>().ImplementedBy<RegionOneA>(),
            Component.For<IView>().ImplementedBy<RegionOneB>(),
            Component.For<IView>().ImplementedBy<RegionTwoA>()
            );
    }

    public IView[] GetAllViewsInRegion(string regionName)
    {
        return _container.Kernel.GetHandlers(typeof (IView))
            .Where(h => IsInRegion(h.ComponentModel.Implementation, regionName))
            .Select(h => _container.Kernel.Resolve(h.ComponentModel.Name, typeof (IView)) as IView)
            .ToArray();
    }

    private bool IsInRegion(Type implementation,
                            string regionName)
    {
        var attr =
            implementation.GetCustomAttributes(typeof (RegionAttribute), false).SingleOrDefault() as RegionAttribute;
        return attr != null && attr.Name == regionName;
    }

    public void Dispose()
    {
        _container.Dispose();
    }
}

public interface IView {}

[Region("One")]
public class RegionOneA : IView {}

[Region("One")]
public class RegionOneB : IView {}

[Region("Two")]
public class RegionTwoA : IView {}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class RegionAttribute : Attribute
{
    private readonly string _name;

    public RegionAttribute(string name)
    {
        _name = name;
    }

    public string Name
    {
        get { return _name; }
    }
}
person Stuart Lange    schedule 27.02.2012
comment
Я тоже пытаюсь использовать типы вместо строковых ключей, но точка расширения Prism, с которой я работаю (RegionBehavior), связывает регионы со строками, поэтому я не вижу никакого способа обойти выбор по строке. На самом деле Prism ожидает только объекты в этом регионе, поэтому даже интерфейс IView - это искусственное упрощение с моей стороны. В редакции 1 я дал кучу контекста для своего вопроса, но я думаю, что это отпугивало людей. - person Joel V. Earnest-DeYoung; 28.02.2012
comment
Некоторые регионы определены в плагинах. Все становится очень сложным и медленным, если моему классу приходится искать в загруженных сборках интерфейс маркера с коротким именем "I" + regionName + "View". Я бы предпочел декорировать классы настраиваемым атрибутом, например ViewExport[RegionName="MainRegion"], и типами фильтров в чем-то вроде точки расширения Windsor HandlersFilter. - person Joel V. Earnest-DeYoung; 28.02.2012
comment
Хорошо, я понимаю, я не знаком с Prism, поэтому я не понимал, что выбор струны был необходим. Думаю, что-то подобное должно быть возможно. Попробую сегодня что-нибудь придумать в свободное время :-) - person Stuart Lange; 28.02.2012
comment
Хорошо, у меня есть кое-что. Мне это не нравится, так как он требует ссылки на контейнер и требует от вас проверки ядра. Логика, вероятно, может быть инкапсулирована в средство, чтобы избежать прямой ссылки на контейнер, но этот базовый подход - единственный способ, который я могу придумать, чтобы решить проблему. - person Stuart Lange; 29.02.2012
comment
Если вы упаковываете свой код из GetAllViewsInRegion в переопределение DefaultTypedFactoryComponentSelector.BuildFactoryComponent, то это совершенно элегантное решение. :-) Отлично! - person Joel V. Earnest-DeYoung; 01.03.2012