Как разрешить сбор с параметром фильтрации? - PullRequest
7 голосов
/ 22 февраля 2012

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

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

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

Я пытался сделать это с помощью Типовой фабрики Замка, Участников строительства ComponentModel и Селекторов обработчиков, но я не могу понять, как отобразить несколько типов в строку так, как Касл может получить к ней доступ, или как Расширьте Castle, чтобы проверить строку, когда он решает, какие типы попытаться разрешить и вернуть в контейнер.

1 Ответ

1 голос
/ 27 февраля 2012

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

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

Обновление: , поскольку мы подтвердили, что в этом случае необходим выбор по строке, лучшее решение, которое я вижу, - просто проверить список обработчиков в ядре, которые удовлетворяют службе 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; }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...