JasperFx / lamar

Fast Inversion of Control Tool and Successor to StructureMap
https://jasperfx.github.io/lamar
MIT License
568 stars 119 forks source link

Is it possible to get Lamar to handle polymorphic dispatch? #174

Closed hellfirehd closed 5 years ago

hellfirehd commented 5 years ago
public class LamarPolymorphicDispatch
{
    [Fact]
    public void Verify()
    {
        var events = new ConcurrentQueue<string>();

        using var _container = new Container(c =>
        {
            c.For<ConcurrentQueue<string>>().Use(events);
            c.For<IHandleMessages<ISomeInterface>>().Use<Handler1>();
            c.For<IHandleMessages<SomeMessage>>().Use<Handler2>();
        });

        var handlers = _container.GetAllInstances<IHandleMessages<ISomeInterface>>();

        foreach (var handler in handlers)
        {
            handler.Handle(new SomeMessage());
        }

        events.ToArray().Should().Contain(new[]
        {
            "Handled by Handler1",
            "Handled by Handler2",
        });
    }

    public interface IHandleMessages
    {
    }

    public interface IHandleMessages<in TMessage> : IHandleMessages
    {
        Task Handle(TMessage message);
    }

    public interface ISomeInterface { }

    public class SomeMessage : ISomeInterface { }

    public class Handler1 : IHandleMessages<ISomeInterface>
    {
        readonly ConcurrentQueue<string> _events;

        public Handler1(ConcurrentQueue<string> events) => _events = events;

        public Task Handle(ISomeInterface message)
        {
            _events.Enqueue($"Handled by Handler1");
            return Task.CompletedTask;
        }
    }
    public class Handler2 : IHandleMessages<SomeMessage>
    {
        readonly ConcurrentQueue<string> _events;

        public Handler2(ConcurrentQueue<string> events) => _events = events;

        public Task Handle(SomeMessage message)
        {
            _events.Enqueue("Handled by Handler2");
            return Task.CompletedTask;
        }
    }
}

If so, how do I configure the container to get this test to pass?

jeremydmiller commented 5 years ago

Are you building your own kind of MediatR tool? That seems to usually end up in some kind of generics hell.

Yes, but it's not really idiomatic Lamar usage. See the "Finding all Possible Implementors of an Interface" section of this: https://jasperfx.github.io/lamar/documentation/ioc/diagnostics/using-the-container-model/. I'd probably try to push you toward custom type scanning registrations and get that sorted out upfront instead of depending on the runtime check above.

hellfirehd commented 5 years ago

I'm just trying to get Rebus to deliver messages to handlers but the messages are Interfaces.

(Why not just use NServiceBus? Because $$$$)

jeremydmiller commented 5 years ago

@hellfirehd If you want help w/ a custom registration convention, let me know. If this is for a per-command activation, that Container.Model based approach is maybe too slow. Otherwise I'm gonna shut this one down.