Is selection by string strictly necessary? Would it be possible to instead have all IView implementations in the same "region" implement a dedicated interface that derives from IView? Then you could use WindsorContainer.ResolveAll() (passing your region-specific IView as T) to resolve the implementations for the region in question (or you could use one of the Collection Resolvers to perform constructor injection).
In general, when trying to do things like this with Windsor, I make every effort to use the type system (and Windsor's support thereof) before resorting to string-based solutions.
Update: since we confirmed that selection by string is necessary in this case, the best solution I see is to simply inspect the list of handlers in the kernel that satisfy the IView service, then filter for the implementers where the region (defined via attribute) matches what we want, then resolve those implementers. This feels a bit hackish, but if you're okay with having a direct reference to the container in your IViewFactory implementation, this appears to work fine. Below is a passing test case demonstrating the solution.
[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; }
}
}