views:

23

answers:

0

Here are the relevant types and an example of the handler I want linked to IHandle<EventA> and IHandle<EventB>:

// marker interface
public interface IEvent {}

public interface IHandle<TEvent> where TEvent : IEvent {
    void Handle(TEvent e);
}

public class SomeHandler : IHandle<EventA>, IHandle<EventB> {
    public void Handle(EventA e) {}
    public void Handle(EventB e) {}
}

I want use the scanner to automatically link SomeHandler as the implementation for both IHandle<EventA> and IHandle<EventB>. I don't want to have to manually specify handlers for each event.

Right now I have the following:

public IContainer CreateContainer(params Assembly[] assemblies) {
    var container = new Container();

    container.Configure(
        config => config.Scan(
            scanner => {
                foreach (var assembly in assemblies) {
                    scanner.Assembly(assembly);
                }

                // 1 - begin
                scanner.Convention<HandlerConvention>();
                // 1 - end
            }
        )
     );
 }

and

public class HandlerConvention : IRegistrationConvention {
    public void Process(Type type, Registry registry) {
        // find all IHandle<> interfaces that this type implements
        var interfaces = from t in type.GetInterfaces()
                         where t.IsGenericType
                               && t.GetGenericTypeDefinition()
                                   .IsAssignableFrom(typeof(IHandle<>))
                         select t;

        // register this type for each IHandle<> that it implements
        foreach (var i in interfaces) {
            registry.AddType(i, type);
        }
    }
}

At first I tried using scanner.ConnectImplementationsToTypesClosing(typeof(IHandle<>)); instead of using the code in // 1 and the convention. That didn't work. Trying to do it that way assigned SomeHandler only to the IHandle<EventA>. It missed assigning it to IHandle<EventB>.

After digging through the StructureMap code for a bit, I found that it eventually calls an extension method on Type called FindInterfaceThatCloses(this Type type, Type openType). That returns only the first interface implemented by type that closes openType instead of all interfaces implemented by type that close openType.

Is there a way to do this with less code?