Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用筛选参数解析集合?_C#_Dependency Injection_Castle Windsor_Prism - Fatal编程技术网

C# 如何使用筛选参数解析集合?

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可以访问的方式将多个类型映射

Castle Windsor能否解析由字符串参数筛选的集合

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
的重写中,那么这是一个完美的解决方案。:-)这太棒了!