简体   繁体   English

Ninject 映射到泛型类型

[英]Ninject mapping to generic type

I have a bunch of events which are processed by event handlers such as the following:我有一堆由事件处理程序处理的事件,例如:

Event Handler:事件处理程序:

public class DeliveryEventHandlers :
IConsume<DeliveryCreated>,
IConsume<DeliveryUpdated>{

readonly IDocumentSession _documentSession;

public DeliveryEventHandlers(IDocumentSession documentSession)
{
    _documentSession = documentSession;
}

public void Consume(DeliveryCreated @event)
{
    //...
}

public void Consume(DeliveryUpdated @event)
{
    //...
}
...

Events:事件:

public class DeliveryCreated : IEvent
{
    public Guid DeliveryId { get; set; }
    ...
}

public class DeliveryUpdated : IEvent
{
    public Guid DeliveryId { get; set; }
    ...
}

And I need to write a Ninject binding that will on request of an Event type, give me the Event handler(s) that consume those events.我需要编写一个 Ninject 绑定,它将根据事件类型的请求,为我提供使用这些事件的事件处理程序。 This is what I have come up with:这是我想出的:

public void BindEventHandlers(IContext context) {
        Kernel.Bind(x =>
        {
            x.FromAssemblyContaining(typeof(DeliveryCreated))
            .SelectAllClasses()
            .InheritedFrom<IEvent>()
            .BindWith(new EventBindingGenerator());
        });
    }

    public class EventBindingGenerator : IBindingGenerator
    {
        public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
        {
            yield return bindingRoot.Bind(x =>
            {
                x.FromAssemblyContaining(typeof(DeliveryEventHandlers))
                .SelectAllClasses()
                .InheritedFrom(IConsume<typeof(type)>);
                // This Part ^
            });
        }
    }

but this will not actually compile - I have hit a snag on the line above the comment: // This Part ^但这实际上不会编译 - 我在评论上方的行上遇到了障碍://这部分^

I need to do a query for:我需要查询:

_context.Get<DeliveryCreated>() 

and recieive a DeliveryCreatedEventHandler.并接收 DeliveryCreatedEventHandler。

Any help would be muchos appreciated!!任何帮助将不胜感激!

Thanks, H谢谢,H

This can actually be solved quite easily with the conventions extension functionality:这实际上可以通过约定扩展功能很容易地解决:

kernel.Bind(x => x.FromAssemblyContaining(typeof(DeliveryCreated))
    .IncludingNonePublicTypes() // may not be needed in your case
    .SelectAllClasses()
    .InheritedFrom(typeof(IConsume<>))
    .BindAllInterfaces());

the following test succeeds (syntax is from FluentAssertions ):以下测试成功(语法来自FluentAssertions ):

kernel.Get<IConsume<DeliverCreated>>().Should().BeOfType<DeliveryEventHandlers>();
kernel.Get<IConsume<DeliveryUpdated>>().Should().BeOfType<DeliveryEventHandlers>();

Alternatively, if you want to make sure you don't want to bind the IConsume<...> implementations to more types than necessary, you can replace the BindAllInterfaces statement as follows:或者,如果您想确保不想将IConsume<...>实现绑定到更多类型,您可以按如下方式替换BindAllInterfaces语句:

private static IEnumerable<Type> SelectConsumeInterfacesOnly(
    Type type, IEnumerable<Type> baseTypes)
{
    var matchingTypes = baseTypes.Where(t => 
         t.IsGenericType
         && t.GetGenericTypeDefinition() == typeof (IConsume<>));
    return matchingTypes;
}

kernel.Bind(x => x.FromThisAssembly()
    .IncludingNonePublicTypes()
    .SelectAllClasses()
    .InheritedFrom(typeof(IConsume<>))
    .BindSelection(SelectConsumeInterfacesOnly));

Again, I've verified that it actually works.再次,我已经验证它确实有效。

You can manually scan the assembly and register all classes that implement the IConsumer<> interface.您可以手动扫描程序集并注册所有实现IConsumer<>接口的类。 Like this:像这样:

foreach (Type type in assembly.GetTypes().Where(x => x.IsClass))
{
    foreach (
        var @interface in
            type.GetInterfaces()
                .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IConsume<>)))
    {
        kernel.Bind(@interface).To(type);
    }
}

If you know that there will be a single consumer of the event, use the following:如果您知道该事件将只有一个使用者,请使用以下命令:

var single_consumer = kernel.Get<IConsume<DeliveryCreated>>();

In case that there can be multiple consumers, use the following to obtain all of them:如果可以有多个消费者,请使用以下方法获取所有消费者:

var all_consumers = kernel.GetAll<IConsume<DeliveryCreated>>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM