Как программно зарегистрировать компонент, который зависит от списка уже зарегистрированных компонентов, с помощью Castle Windsor? - PullRequest
3 голосов
/ 15 января 2010

Я программно регистрирую группу сервисов, которые все реализуют один и тот же интерфейс, IRule. У меня есть другой сервис, который выглядит так:

public class MyService {
    private IEnumerable<IRule> _rules;
    public MyService(IEnumerable<IRule> rules){
        _rules = rules;
    }
}

Хаммет опубликовал что-то похожее на то, что я хотел, http://hammett.castleproject.org/?p=257. Я изменил подпись на IRule [] и попробовал трюк с ArrayResolver, но это не сработало для меня (заметьте, это не сработало) что-нибудь сломать тоже).

Кто-нибудь знает, как программно зарегистрировать компонент, подобный приведенному выше коду?

Ответы [ 2 ]

6 голосов
/ 15 января 2010

Если вы не хотите изменять подпись MyService и продолжаете использовать IEnumerable<IRule>, вы также можете создать собственный ISubDependencyResolver. Вот что мы сделали:

public class EnumerableResolver : ISubDependencyResolver
{
    private readonly IKernel kernel;

    public EnumerableResolver(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
    {
        Type targetType = dependency.TargetType;
        if (targetType == null)
        {
            throw new ArgumentException("TargetType property cannot be null", "dependency");
        }

        if (targetType.IsGenericType && (targetType.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
        {
            Type service = targetType.GetGenericArguments()[0];
            return this.kernel.HasComponent(service);
        }
        return false;
    }

    public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
    {
        Type service = dependency.TargetType.GetGenericArguments()[0];
        Array array = this.kernel.ResolveAll(service, (IDictionary)null);
        return Activator.CreateInstance(typeof(List<>).MakeGenericType(new Type[] { service }), new object[] { array });
    }
}

Он должен быть зарегистрирован в контейнере следующим образом:

container.Kernel.Resolver.AddSubResolver(new EnumerableResolver(this.Kernel));
2 голосов
/ 15 января 2010

Я загрузил источник для Castle.MicroKernel и заметил, что уже есть ArrayResolver и ListResolver (в пространстве имен Castle.MicroKernel.Resolvers.SpecializedResolvers). Код, который я скопировал (вслепую) из блога Хаммета, не работал, скорее всего потому, что с момента его написания структура изменилась.

Вот пример проекта, демонстрирующего, как это сделать: http://www.panteravb.com/downloads/WindsorCon.zip

Я попробовал и ArrayResolver, и ListResolver, и они оба работали без проблем, это довольно просто, поэтому предположим, что класс обслуживания:

public class MyService
{
    private IEnumerable<IRule> _rules;
    public MyService(IList<IRule> rules)
    {
        _rules = rules;
    }
}

Вы можете зарегистрировать этого парня так:

private IWindsorContainer _container;
private void InitializeIoc()
{
    _container = new WindsorContainer();
    _container.Kernel.Resolver.AddSubResolver(new ListResolver(_container.Kernel));
    _container.Register(Component.For<IRule>().ImplementedBy<Rule1>());
    _container.Register(Component.For<IRule>().ImplementedBy<Rule2>());
    _container.Register(Component.For<MyService>());
}
...