简体   繁体   中英

Registration of Concrete Type with Derived Interface

Wondering how to register these types given their inheritence, etc...

public interface ICommandHandler<in TCommand>
{
    void Handle(TCommand command);         
}

public abstract class AbstractCommandHandler<T> : ICommandHandler<T>
{
    public abstract void Handle(T command);
}

public interface ILoginCommandHandler : ICommandHandler<object>{}

public class LoginCommandHandler : AbstractCommandHandler<object>, ILoginCommandHandler
{
    public override void Handle(object command){}
}

Currently, I'm doing the following:

var container = new Container();

container.Register<ICommandHandler<object>, LoginCommandHandler>();
container.Register<ILoginCommandHandler, LoginCommandHandler>();

container.Verify();

var instance = container.GetInstance<ILoginCommandHandler>();
instance.Handle(new object());

This works, but I'm wondering if this is the correct method. The ILoginCommandHandler is just an easier way to identify the command and reduce code clutter. In addition I can add specific other methods there if I need at later point.

Also, I'm going to have at least one hundred of these so I'm going to want to use a package inside each satellite assembly. What's the best method for registering packages from multiple satellite assemblies. I have found that sometimes SimpleInjector didn't like where I placed the registrations (or I just did it wrong).

I understand how you try to minimize the use of generic typing from your code, but by doing this you completely disallow generic decoratos to be applied. Being able to easily apply decorators around a large range of command handler implementations is one of the strongest arguments for using the ICommandHandler<T> abstraction. Just by using the following registration for instance:

container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerDecorator<>));

container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(DeadlockRetryCommandHandlerDecorator<>));

container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(ValidationCommandHandlerDecorator<>));

container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(SecurityCommandHandlerDecorator<>));

However, if you wish to resolve a ILoginCommandHandler , that means that all registered decorators need to implement ILoginCommandHandler . Otherwise your container will never be able to return such decorator. Applying one or two of those interfaces on your decorators wouldn't be that bad, but if you "going to have at least one hundred of these" interfaces, this will lead to an unworkable situation.

And even if you don't have any decorators at the moment, I would advice against doing this, because having these interfaces completely disallows adding cross-cutting concerns in the future, which will lead to a situation with much more code clutter as what you're currently seeing with the extra amount of generic typing.

I can add specific other methods there if I need at later point.

You shouldn't do this, because that completely conflicts with the principles where this pattern is based on. Why would a consumer need more methods for executing that use case? Are those two methods two different use cases? Is one of those methods a query ? You will be breaking three out of five SOLID principles when you do that (as explained here ). And it again disallows applying cross-cutting concerns and don't forget that by introducing hundreds of interfaces, you're again introducing complexity. Now you've got one very simple (generic) abstraction. That makes your application design very clear.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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