Castle Windsor Fluent API: определение массива с отдельным элементом в качестве зависимости - PullRequest
1 голос
/ 01 июня 2009

Учитывая эту конфигурацию XML (которая работает)

<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" /> 

Я перешел на свободный API, как показано ниже (что не работает):

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
);

Когда я сейчас пытаюсь разрешить экземпляр X.Y.Z.ActivityService, Виндзор выбрасывает NotImplementedException в Castle.MicroKernel.SubSystems.Conversion.ArrayConverter.PerformConversion(String, Type).

Реализация метода PerformConversion:

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

Я должен добавить, что если я удаляю вызов ServiceOverrides, все ведет себя как ожидалось. Так что в том, как я подключаю параметр Listeners, что-то не так. Кстати, слушатели - это свойство, а не параметр конструктора.

Видя, как конфигурация XML работает, как и ожидалось, как лучше всего использовать свободный API (если не использовать метод PerformConversion) для достижения того же результата?

Я использую версию 2.0.

EDIT

Я расширю вопрос о том, как бы вы достигли этой конфигурации в коде с использованием или без использования свободного API.

UPDATE

Похоже, проблема возникает, если вы пытаетесь назначить отдельный элемент для свойства массива. Модульные тесты, представленные ниже, чтобы проиллюстрировать проблему.

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");
    }
}

Вопрос все еще стоит.

Спасибо.

1 Ответ

3 голосов
/ 02 июня 2009
[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; }
}

Ключевой частью здесь является new[] {"listener"}. MicroKernel должен знать, что параметр listeners является массивом, если вы передаете просто «listener», он предполагает, что параметр является скалярным и выдает, потому что он не может преобразовать скаляр в массив.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...