Reputation: 41902
My application has two command classes FooCommand
and BarCommand
, where BarCommand
is a subclass of FooCommand
.
class FooCommand
class BarCommand : FooCommand
I then have classes to execute these commands.
class FooCommandHandler : ICommandHandler<FooCommand>
class BarCommandHandler : ICommandHandler<BarCommand>
These command handlers are registered with Autofac as ICommandHandler<>
services.
builder.RegisterType<FooCommandHandler>.As<ICommandHandler<FooCommand>>();
builder.RegisterType<BarCommandHandler>.As<ICommandHandler<BarCommand>>();
Then when I need to execute a command, I resolve the registered handlers using Autofac's enumeration relationship type, which works fine.
var barCommandHandlers = container.Resolve<IEnumerable<ICommandHandler<FooCommand>>>()
// returns [ FooCommandHandler ]
So far, so good. But when I resolve registered handlers for BarCommand
, Autofac matches both the BarCommandHandler
and FooCommandHandler
implementations because BarCommand
derives from FooCommand
.
var barCommandHandlers = container.Resolve<IEnumerable<ICommandHandler<BarCommand>>>()
// returns [ BarCommandHandler, FooCommandHandler ]
This behaviour isn't too unexpected, but it's not quite what I want.
Is there a way to resolve IEnumerable<ICommandHandler<BarCommand>>
to only provide handlers that directly implement the ICommandHandler<BarCommand>
interface, without also including those that implement ICommandHandler<Base>
?
Upvotes: 2
Views: 165
Reputation: 29252
Too long for a comment: I can't duplicate the behavior. Here are some types and a unit test:
public interface ICommandHandler<T> where T : FooCommand { }
public class FooCommand { }
public class BarCommand : FooCommand { }
class FooCommandHandler : ICommandHandler<FooCommand> { }
class BarCommandHandler : ICommandHandler<BarCommand> { }
class BarCommandHandler2 : ICommandHandler<BarCommand> { }
[TestClass]
public class AutofacTests
{
[TestMethod]
public void ContainerResolvesExpectedDependency()
{
var container = GetContainer();
var barCommandHandlers = container.Resolve<IEnumerable<ICommandHandler<BarCommand>>>()
.ToArray();
Assert.AreEqual(2, barCommandHandlers.Length);
Assert.IsTrue(barCommandHandlers.Any(bch => bch is BarCommandHandler));
Assert.IsTrue(barCommandHandlers.Any(bch => bch is BarCommandHandler2));
Assert.IsFalse(barCommandHandlers.Any(bch => bch is FooCommandHandler));
}
private IContainer GetContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<FooCommandHandler>().As<ICommandHandler<FooCommand>>();
builder.RegisterType<BarCommandHandler>().As<ICommandHandler<BarCommand>>();
builder.RegisterType<BarCommandHandler2>().As<ICommandHandler<BarCommand>>();
return builder.Build();
}
}
I'm registering the various implementations of ICommandHandler<T>
. I included an extra one - BarCommandHandler2
- so I could verify that I'm getting a collection of multiple implementations from the container.
The tests pass. I'm registering all three types, but when I resolve IEnumerable<ICommandHandler<BarCommand>>
I only get the two implementations that I expect.
That makes sense because FooCommandHandler
doesn't implement ICommandHandler<BarCommand>
. If the container did resolve that then it would be a bug.
My recommendation would be to look over the part where you're resolving IEnumerable<ICommandHandler<BarCommand>>
. Perhaps you've got some additional generics at work, and at runtime you're actually resolving something else.
Upvotes: 1