C# 如何使用筛选参数解析集合?
Castle Windsor能否解析由字符串参数筛选的集合C# 如何使用筛选参数解析集合?,c#,dependency-injection,castle-windsor,prism,C#,Dependency Injection,Castle Windsor,Prism,Castle Windsor能否解析由字符串参数筛选的集合 interface IViewFactory { IView[] GetAllViewsInRegion(string regionName); } 我的应用程序将区域定义为IView派生类型的组。当我在运行时显示一个特定的区域时,我想解析其中每一个IView类型的实例(一个la Prism) 我试过用Castle的类型化工厂工具、组件模型构造贡献者和处理程序选择器来实现,但我不知道如何以Castle可以访问的方式将多个类型映射
interface IViewFactory
{
IView[] GetAllViewsInRegion(string regionName);
}
我的应用程序将区域定义为IView派生类型的组。当我在运行时显示一个特定的区域时,我想解析其中每一个IView类型的实例(一个la Prism)
我试过用Castle的类型化工厂工具、组件模型构造贡献者和处理程序选择器来实现,但我不知道如何以Castle可以访问的方式将多个类型映射到字符串,当Castle决定尝试解析哪些类型并返回到容器中时,也不知道如何扩展Castle来检查字符串。是否严格需要按字符串进行选择?是否有可能让同一“区域”中的所有IView实现实现一个从IView派生的专用接口?然后,您可以使用WindsorContainer.ResolveAll()(将特定于区域的IView传递为T)来解析所讨论区域的实现(或者您可以使用一个集合解析程序来执行构造函数注入) 一般来说,在尝试使用Windsor执行类似操作时,我会尽一切努力使用类型系统(以及Windsor对其的支持),然后再求助于基于字符串的解决方案 更新:既然我们确认了在这种情况下按字符串选择是必要的,那么我看到的最好的解决方案就是简单地检查内核中满足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; }
}
}
[测试]
公开无效测试()
{
使用(var factory=new ViewFactory())
{
var regionOneViews=factory.GetAllViewsInRegion(“一”);
Assert.That(regionOneViews,Is.Not.Null);
断言(regionOneViews,Has.Length.EqualTo(2));
Assert.That(regionOneViews,Has.Some.TypeOf());
Assert.That(regionOneViews,Has.Some.TypeOf());
var regiontwviews=factory.GetAllViewsInRegion(“两个”);
Assert.That(regiontwviews,Is.Not.Null);
Assert.That(regiontwviews,Has.Length.EqualTo(1));
Assert.That(regiontwviews,Has.Some.TypeOf());
}
}
}
公共接口IViewFactory
{
IView[]GetAllViewsInRegion(字符串regionName);
}
公共类ViewFactory:IViewFactory,IDisposable
{
私人只读WindsorContainer\u容器;
公共视图工厂()
{
_容器=新WindsorContainer();
_集装箱。登记(
Component.For().ImplementedBy(),
Component.For().ImplementedBy(),
Component.For().ImplementedBy()实现
);
}
public IView[]GetAllViewsInRegion(字符串regionName)
{
return _container.Kernel.GetHandlers(typeof(IView))
.Where(h=>IsInRegion(h.ComponentModel.Implementation,regionName))
.Select(h=>_container.Kernel.Resolve(h.ComponentModel.Name,typeof(IView))作为IView)
.ToArray();
}
私有布尔IsInRegion(类型实现,
字符串(区域名称)
{
var属性=
GetCustomAttributes(typeof(RegionaAttribute),false).SingleOrDefault()作为RegionaAttribute;
返回attr!=null&&attr.Name==regionName;
}
公共空间处置()
{
_container.Dispose();
}
}
公共接口IView{}
[区域(“一”)]
公共类区域:IView{}
[区域(“一”)]
公共类RegionOneB:IView{}
[区域(“两个”)]
公共类RegionTwoA:IView{}
[AttributeUsage(AttributeTargets.Class,AllowMultiple=false)]
公共类RegionAttribute:属性
{
私有只读字符串\u名称;
公共RegionAttribute(字符串名称)
{
_名称=名称;
}
公共字符串名
{
获取{return\u name;}
}
}
我也尝试使用类型而不是字符串键,但我正在使用的棱柱扩展点(RegionBehavior)将区域与字符串相关联,因此我看不到任何通过字符串进行选择的方法。实际上,Prism只希望该区域中有对象,所以就我而言,即使是IView界面也是一种人工简化。在本文中,我为我的问题提供了大量的上下文,但我认为这吓跑了人们。一些区域是在插件中定义的。如果我的类必须在加载的程序集中搜索短名称为“I”+regionName+“View”
的标记接口,那么事情就会变得非常复杂和缓慢。我更喜欢用自定义属性来装饰类,比如ViewExport[RegionName=“MainRegion”]
和Windsor的HandlersFilter扩展点中的过滤器类型。好吧,我知道,我不熟悉Prism,所以我没有意识到字符串选择是必要的。我认为这样的事情应该是可能的。今天我想在业余时间想点什么:-)好吧,我有点东西。我不喜欢它,因为它需要对容器的引用,并且需要您检查内核。逻辑可能可以封装到一个工具中,以避免直接引用容器,但这种基本方法是我能想到的唯一解决问题的方法。如果您将GetAllViewsInRegion
中的代码打包到DefaultTypedFactoryComponentSelector.BuildFactoryComponent
的重写中,那么这是一个完美的解决方案。:-)这太棒了!