温莎城堡流利的API:作为与依赖单项定义数组 [英] Castle Windsor Fluent API: Define Array with Single item as Dependency

查看:162
本文介绍了温莎城堡流利的API:作为与依赖单项定义数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于这种XML配置(工作)

 <成分TYPE =X.Y.Z.ActivityService,X.Y.Z.ServicesID =X.Y.Z.ActivityService生活方式=瞬时>
  <&参数GT;
    <&听众GT;
      <阵列GT;
        <项目> $ {DefaultActivityListener}< /项目>
      < /阵列>
    < /听众>
  < /参数>
< /成分><成分TYPE =X.Y.Z.DefaultActivityListener,X.Y.Z.ServicesID =DefaultActivityListener生活方式=瞬时/>

我已经转换到使用流畅API如下(不工作):

  Container.Register(
    Component.For< X.Y.Z.ActivityService>()
    .ServiceOverrides(
        ServiceOverride.ForKey(监听器​​)。方程(typeof运算(X.Y.Z.DefaultActivityListener).Name点))
    .LifeStyle.Transient
);Container.Register(
    Component.For< X.Y.Z.DefaultActivityListener>()
    .Named(DefaultActivityListener)
    .LifeStyle.Transient
);

当我现在试图解决 XYZActivityService 的一个实例温莎抛出一个 NotImplementedException Castle.MicroKernel.SubSystems.Conversion.ArrayConverter.PerformConversion(字符串型)

在PerformConversion方法的实现是:

 公众覆盖对象PerformConversion(字符串值,类型TARGETTYPE)
{
    抛出新NotImplementedException();
}

我要补充一点,如果我删除 ServiceOverrides 通话,所有的行为与预期相同。因此,有明确一些错误,我布线​​了监听器参数的方式。顺便说一句听众是一个属性,而不是一个构造函数的参数。

看到的XML配置按预期工作我如何最好地利用流利的API(简称实施PerformConversion方法),以达到相同的结果?

我使用的2.0版。

修改

我将延长问题,你将如何实现code这个配置,使用或不使用流畅的API。

更新

看来,如果你试图将一个单一的元素赋值给一个数组属性出现问题。下面提供了单元测试来说明问题。

 命名空间组件
{
    大众A级
    {
        公共I [] I {搞定;组; }
    }    公共接口I
    {
        字符串名称{; }
    }    公共类B:我
    {
        公共字符串名称{{返回B; }}
    }    公共类C:我
    {
        公共字符串名称{{返回的C; }}
    }
}
[测试方法]
公共无效ArrayPropertyTestApi()
{
    //代用证
    使用(Castle.Windsor.WindsorContainer集装箱=新Castle.Windsor.WindsorContainer())
    {
        container.Register(Component.For<Components.A>().ServiceOverrides(ServiceOverride.ForKey(\"I\").Eq(typeof(Components.B).FullName, typeof运算(Components.C).FullName)));
        container.Register(Component.For&所述; Components.B&GT;());
        container.Register(Component.For&所述; Components.C&GT;());        Components.A SVC = container.Resolve&LT; Components.A&GT;();
        Assert.IsTrue(svc.I.Length == 2);
        Assert.IsTrue(svc.I [0] .Name点==B);
        Assert.IsTrue(svc.I [1] .Name点==C);
    }
}[测试方法]
公共无效ArrayPropertyTestApi2()
{
    //方式无法
    使用(Castle.Windsor.WindsorContainer集装箱=新Castle.Windsor.WindsorContainer())
    {
        container.Register(Component.For<Components.A>().ServiceOverrides(ServiceOverride.ForKey(\"I\").Eq(typeof(Components.B).FullName)));
        container.Register(Component.For&所述; Components.B&GT;());
        container.Register(Component.For&所述; Components.C&GT;());        Components.A SVC = container.Resolve&LT; Components.A&GT;(); //抛出NotImplementedException
        Assert.IsTrue(svc.I.Length == 1);
        Assert.IsTrue(svc.I [0] .Name点==B);
    }
}

问题仍然有效。

感谢。


解决方案

  [的TestFixture]
公共类WindsorTests {    [测试]
    公共无效ArrayConfig(){
        VAR集装箱=​​新WindsorContainer();
        container.Register(Component.For&LT;听者GT;()命名(监听器​​)。);
        container.Register(Component.For&LT; ActivityService&GT;()
            .ServiceOverrides(ServiceOverride.ForKey(监听器​​),方程(新[] {监听器​​})));
        VAR的服务= container.Resolve&LT; ActivityService&GT;();
        Assert.AreEqual(1,service.Listeners.Length);
    }
}公共类监听{}公共类ActivityService {
    公共监听[] {听众获得;组; }
}

这里的关键部分是新[] {监听器​​} 。微内核需要知道该参数的听众是一个数组,如果你通过只是监听器​​,它假定参数是标量,并抛出,因为它不能标量转换成数组。

Given this XML configuration (which works)

<component type="X.Y.Z.ActivityService, X.Y.Z.Services" id="X.Y.Z.ActivityService" lifestyle="transient">
  <parameters>
    <Listeners>
      <array>
        <item>${DefaultActivityListener}</item>
      </array>
    </Listeners>
  </parameters>
</component>

<component type="X.Y.Z.DefaultActivityListener, X.Y.Z.Services" id="DefaultActivityListener" lifestyle="transient" />

I have converted to use the fluent API as below (which doesn't work):

Container.Register(
    Component.For<X.Y.Z.ActivityService>()
    .ServiceOverrides(
        ServiceOverride.ForKey("Listeners").Eq(typeof(X.Y.Z.DefaultActivityListener).Name))
    .LifeStyle.Transient
);

Container.Register(
    Component.For<X.Y.Z.DefaultActivityListener>()
    .Named("DefaultActivityListener")
    .LifeStyle.Transient
);

When I now attempt to resolve an instance of X.Y.Z.ActivityService Windsor throws a NotImplementedException in Castle.MicroKernel.SubSystems.Conversion.ArrayConverter.PerformConversion(String, Type).

The implementation of the PerformConversion method is:

public override object PerformConversion(String value, Type targetType)
{
    throw new NotImplementedException();
}

I should add that if I remove the ServiceOverrides call, all behaves as expected. So there is specifically something wrong in the way I am wiring up the Listeners parameter. Listeners by the way is a property as opposed to a constructor parameter.

Seeing as the XML config works as expected how do I best use the fluent API (short of implementing the PerformConversion method) in order to achieve the same result?

I am using Release 2.0.

EDIT

I will extend the question to how would you achieve this configuration in code, with or without use of the fluent API.

UPDATE

It appears the problem occurs if you attempt to assign a single element to an array property. Unit tests provided below to illustrate issue.

namespace Components
{
    public class A
    {
        public I[] I { get; set; }
    }

    public interface I
    {
        string Name { get; }
    }

    public class B : I
    {
        public string Name { get { return "B"; } }
    }

    public class C : I
    {
        public string Name { get { return "C"; } }
    }
}


[TestMethod]
public void ArrayPropertyTestApi()
{
    //PASSES
    using (Castle.Windsor.WindsorContainer container = new Castle.Windsor.WindsorContainer())
    {
        container.Register(Component.For<Components.A>().ServiceOverrides(ServiceOverride.ForKey("I").Eq(typeof(Components.B).FullName, typeof(Components.C).FullName)));
        container.Register(Component.For<Components.B>());
        container.Register(Component.For<Components.C>());

        Components.A svc = container.Resolve<Components.A>();
        Assert.IsTrue(svc.I.Length == 2);
        Assert.IsTrue(svc.I[0].Name == "B");
        Assert.IsTrue(svc.I[1].Name == "C");
    }
}

[TestMethod]
public void ArrayPropertyTestApi2()
{
    //FAILS
    using (Castle.Windsor.WindsorContainer container = new Castle.Windsor.WindsorContainer())
    {
        container.Register(Component.For<Components.A>().ServiceOverrides(ServiceOverride.ForKey("I").Eq(typeof(Components.B).FullName)));
        container.Register(Component.For<Components.B>());
        container.Register(Component.For<Components.C>());

        Components.A svc = container.Resolve<Components.A>(); //Throws NotImplementedException
        Assert.IsTrue(svc.I.Length == 1);
        Assert.IsTrue(svc.I[0].Name == "B");
    }
}

Question still stands.

Thanks.

解决方案

[TestFixture]
public class WindsorTests {

    [Test]
    public void ArrayConfig() {
        var container = new WindsorContainer();
        container.Register(Component.For<Listener>().Named("listener"));
        container.Register(Component.For<ActivityService>()
            .ServiceOverrides(ServiceOverride.ForKey("listeners").Eq(new[] {"listener"})));
        var service = container.Resolve<ActivityService>();
        Assert.AreEqual(1, service.Listeners.Length);
    }
}

public class Listener {}

public class ActivityService {
    public Listener[] Listeners { get; set; }
}

The key part here is the new[] {"listener"}. The MicroKernel needs to know that the parameter listeners is an array, if you pass just "listener" it assumes that the parameter is scalar and throws because it can't convert a scalar to an array.

这篇关于温莎城堡流利的API:作为与依赖单项定义数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆