Autofac: Hiding multiple contravariant implementations behind one composite - c#

I was triggered by this SO question about (.NET 4.0) covariance and contravariance support for Autofac, and now I'm trying to achieve something similar, but without any luck.
What I am trying to achieve is configure Autofac in such way that when I resolve a single concrete IEventHandler<TEvent> (for the sake of demonstration using container.Resolve, but normally of course using constructor injection), Autofac will return me a MultipleDispatchEventHandler<TEvent> that wraps all registered event handlers that are assignable from the requested handler.
In other words, when I write this:
var handler = container
.GetInstance<IEventHandler<CustomerMovedEvent>>();
handler.Handle(new CustomerMovedEvent());
With respect to the application design (given below), I'd expect a MultipleDispatchEventHandler<CustomerMovedEvent> to be returned that wraps both a CustomerMovedEventHandler and a NotifyStaffWhenCustomerMovedEventHandler.
Here is the application design:
// Events:
public class CustomerMovedEvent { }
public class CustomerMovedAbroadEvent : CustomerMovedEvent { }
public class SpecialCustomerMovedEvent : CustomerMovedEvent { }
// Event handler definition (note the 'in' keyword):
public interface IEventHandler<in TEvent>
{
void Handle(TEvent e);
}
// Event handler implementations:
public class CustomerMovedEventHandler
: IEventHandler<CustomerMovedEvent>
{
public void Handle(CustomerMovedEvent e) { ... }
}
public class NotifyStaffWhenCustomerMovedEventHandler
: IEventHandler<CustomerMovedEvent>
{
public void Handle(CustomerMovedEvent e) { ... }
}
public class CustomerMovedAbroadEventHandler
: IEventHandler<CustomerMovedAbroadEvent>
{
public void Handle(CustomerMovedAbroadEvent e) { ... }
}
This is the definition of the MultipleDispatchEventHandler<TEvent>, defined in the Composition Root:
// A composite wrapping possibly multiple handlers.
public class MultipleDispatchEventHandler<TEvent>
: IEventHandler<TEvent>
{
private IEnumerable<IEventHandler<TEvent>> handlers;
public MultipleDispatchEventHandler(
IEnumerable<IEventHandler<TEvent>> handlers)
{
this.handlers = handlers;
}
public void Handle(TEvent e)
{
this.handlers.ToList().ForEach(h => h.Handle(e));
}
}
This is my current configuration:
var builder = new ContainerBuilder();
// Note the use of the ContravariantRegistrationSource (which is
// available in the latest release of Autofac).
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IEventHandler<>).Assembly)
.AsClosedTypesOf(typeof(IEventHandler<>));
// UPDATE: I'm registering this last as Kramer suggests.
builder.RegisterGeneric(typeof(MultipleDispatchEventHandler<>))
.As(typeof(IEventHandler<>)).SingleInstance();
var container = builder.Build();
With the current configuration, the application fails during the call to Resolve, with the following exception:
Autofac.Core.DependencyResolutionException: Circular component
dependency detected:
MultipleDispatchEventHandler'1[[SpecialCustomerMovedEvent]] ->
IEventHandler'1[[SpecialCustomerMovedEvent]][] ->
MultipleDispatchEventHandler'1[[SpecialCustomerMovedEvent]].
Now the question is of course: how can I fix the configuration (or the design) to support this?

I'm going to make this a separate answer instead of modifying my other one. This one solves the example scenario without using a composite.
Working Code
I added a static int handleCount to each of the event handlers for testing purposes, like this:
public class CustomerMovedEventHandler
: IEventHandler<CustomerMovedEvent>
{
public static int handleCount = 0;
public void Handle(CustomerMovedEvent e) { handleCount++; }
}
Here's a passing test that demonstrates that the events are going where they should:
var builder = new ContainerBuilder();
builder.RegisterSource(new Autofac.Features
.Variance.ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IEventHandler<>).Assembly)
.AsClosedTypesOf(typeof(IEventHandler<>));
builder.RegisterGeneric(typeof(EventRaiser<>))
.As(typeof(IEventRaiser<>));
var container = builder.Build();
Assert.AreEqual(0, CustomerMovedEventHandler.handleCount);
Assert.AreEqual(0, NotifyStaffWhenCustomerMovedEventHandler.handleCount);
Assert.AreEqual(0, CustomerMovedAbroadEventHandler.handleCount);
container.Resolve<IEventRaiser<CustomerMovedEvent>>()
.Raise(new CustomerMovedEvent());
Assert.AreEqual(1, CustomerMovedEventHandler.handleCount);
Assert.AreEqual(1, NotifyStaffWhenCustomerMovedEventHandler.handleCount);
Assert.AreEqual(0, CustomerMovedAbroadEventHandler.handleCount);
container.Resolve<IEventRaiser<CustomerMovedAbroadEvent>>()
.Raise(new CustomerMovedAbroadEvent());
Assert.AreEqual(2, CustomerMovedEventHandler.handleCount);
Assert.AreEqual(2, NotifyStaffWhenCustomerMovedEventHandler.handleCount);
Assert.AreEqual(1, CustomerMovedAbroadEventHandler.handleCount);
container.Resolve<IEventRaiser<SpecialCustomerMovedEvent>>()
.Raise(new SpecialCustomerMovedEvent());
Assert.AreEqual(3, CustomerMovedEventHandler.handleCount);
Assert.AreEqual(3, NotifyStaffWhenCustomerMovedEventHandler.handleCount);
Assert.AreEqual(1, CustomerMovedAbroadEventHandler.handleCount);
You can see I'm using an IEventRaiser<TEvent> instead of a composite IEventHandler<TEvent>. Here's how it looks:
public interface IEventRaiser<TEvent>
{
void Raise(TEvent e);
}
public class EventRaiser<TEvent> : IEventRaiser<TEvent>
{
List<IEventHandler<TEvent>> handlers;
public EventRaiser(IEnumerable<IEventHandler<TEvent>> handlers)
{
this.handlers = handlers.ToList();
}
public void Raise(TEvent e)
{
handlers.ForEach(h => h.Handle(e));
}
}
Design Thoughts
Avoiding the composite IEventHandler sure makes our work at the composition root easier. We don't have to worry about recursive composition or making sure the composite is the default implementation. But we added a new interface IEventRaiser which might look redundant. Is it? I think not.
Raising an event and handling an event are two different things. IEventHandler is an interface that has to do with handling events. IEventRaiser is an interface that has to do with raising events.
Imagine that I'm a piece of code that wants to raise an event. If I ask the IoC for a single IEventHandler I am introducing coupling that I don't need. I shouldn't need to know about that IEventHandler interface. I shouldn't be asking anyone to Handle my event. All I want to do is Raise it. Handling may or may not happen on the other side; it is irrelevant to me. I'm selfish - I want an interface created solely for me and my need to raise events.
As an event raiser, I intend to raise an event. As an event handler, I intend to handle an event. We have two different intents, so we should have two different interfaces. Just because we could use the same interface and a composite doesn't mean we should.
The Interface Segregation Principle seems to be more about splitting fat interfaces into thinner ones (see also Role Interface). In our case, we don't have a fat interface, but I think we're doing something similar - "Interface Segregation by Intent".
One more thing
In writing this answer I almost articulated a design idiom that I think many of us are familiar with, but I don't think we have standard terminology for it.
"Type C Interface" - frequently Consumed, rarely Implemented. A "service" interface. For example, IEventRaiser or ICustomerRepository. These interfaces probably have only one implementation (maybe decorated a bit) but they are consumed all over the place by code that wants to Raise Events or Save Customers.
"Type I Interface" - frequently Implemented, rarely Consumed. A "plugin" interface. For example, IEventHandler<TEvent>. Consumed in only one place (the EventRaiser) but implemented by many classes.
The same interface should not be both a Type C and a Type I. This is another reason to separate the IEventRaiser (Type C) from the IEventHandler (Type I).
I'm thinking that the composite pattern is only applicable to Type C interfaces.
Please edit or comment if there is standard terminology for what I've called "Type C" and "Type I" interfaces.

+1 for IEventRaiser<T> by #default.kramer. Just for the record, since the linked answer doesn't provide any code, and the configuration for this scenario is a bit less than intuitive because of the generic types involved:
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(...)
.As(t => t.GetInterfaces()
.Where(i => i.IsClosedTypeOf(typeof(IEventHandler<>)))
.Select(i => new KeyedService("handler", i)));
builder.RegisterGeneric(typeof(MultipleDispatchEventHandler<>))
.As(typeof(IEventHandler<>))
.WithParameter(
(pi, c) => pi.Name == "handlers",
(pi, c) => c.ResolveService(
new KeyedService("handler", pi.ParameterType)));

Related

MediatR generic handlers

I use a MediatR library in my Asp .Net core 6 app. And I have a the same logic for a group of requests, so I want to use the same handler for all of them. The problem is not new, but the solutions that I found did not help me. I have my own solution to solve this problem, but I do not like it and hope somebody knows a better way to solve this problem.
The example is shown here:
public class HandlerRequest<T> : IRequest
{
public T Data { get; set; }
}
public class Handler<T> : IRequestHandler<HandlerRequest<T>>
{
public Task<Unit> Handle(HandlerRequest<T> request, CancellationToken cancellationToken)
{
// the logic is here
return Task.FromResult(new Unit());
}
}
The registration of MediatR is as follows:
builder.Services.AddMediatR(typeof(BusinessLayer));
When I try to call my mediatr for example:
await _mediator.Send(new HandlerRequest<int>{Data = 5});
await _mediator.Send(new HandlerRequest<string>{Data = "TEST"});
I get an exception:
Error constructing handler for request of type
MediatR.IRequestHandler2[AT.Messenger.Credentials.Business.Requests.V1.Modeles.HandlerRequest1[System.Int32],MediatR.Unit].
Register your handlers with the container. See the samples in GitHub
for examples.
The problem happens because MediatR can not register generic handler. I also tried to register handler as scoped or singleton service as I've seen that advice on the internet, but it does not help.
The only solution that I found - is inherit a new class from my handler:
public class HandlerInt : Handler<int>
{
}
public class HandlerString : Handler<string>
{
}
If use this approach, all works, but I don't like this solution. If anybody know better way to solve this problem give me an advice please.
You have the following options, first, register what you will need explicitly like this.
services.AddTransient<IRequestHandler<HandlerRequest<int>, Unit>>, Handler<int>>();
//so on and so forth
This way you have registered the handlers for known types.
If you have open-bound generic, you can look into my PR that gives you a
services.RegisterGenericMediatRHandlers(typeof(GenericHandlerBase).Assembly);
to automatically register classes inheriting from the constrained interface by using the method provided above.
Lastly, you can opt to use Autofac and register all your handlers like this:
var mediatrOpenTypes = new[]
{
typeof(IRequestHandler<,>),
typeof(IRequestExceptionHandler<,,>),
typeof(IRequestExceptionAction<,>),
typeof(INotificationHandler<>),
};
foreach (var mediatrOpenType in mediatrOpenTypes)
{
builder
.RegisterAssemblyTypes(_assemblies.ToArray())
.AsClosedTypesOf(mediatrOpenType)
.AsImplementedInterfaces();
}
//also by simply
//builder.RegisterGeneric(typeof(Handler<>)).AsImplementedInterfaces();
This will also register all the generic handlers and you won't even have to register it explicitly inside the DI.
btw
The method you used to handle generic registration is the way described in the docs, to quote
If you have an open generic not listed above, you'll need to register it explicitly. For example, if you have an open generic request handler, register the open generic types explicitly:
services.AddTransient(typeof(IRequestHandler<,>), typeof(GenericHandlerBase<,>));
This won't work with generic constraints, so you're better off creating an abstract base class and concrete closed generic classes that fill in the right types.
Source: docs link
I have colleted a lot of information and figured out a solution to register any kind of generic Mediator Handlers.
I was stuck trying to register one generic implementation with another generic class inside INotificationHandler, like this:
public class DomainEventsDispatcher<TEvent> : INotificationHandler<DomainEventDispatch<TEvent>> where TEvent : DomainEvent
PS: I'll use the example above to explain below.
Obviously, your cannot simply use "services.AddMediatr(typeof(AppAssembly))" because using Mediator with generic types, Handlers are not loaded into DI on startup.
So, I decided to register each implementation of each type of TEvent, however, I did it by looping the assemblies that implemented TEvent type and building each part to be used on services.AddTransient.
Looking for assemblies that implemented TEvent type;
First variable: Build the generic used inside INotificationHandler;
Second variable: Build the INotificationHandler with first variable;
Third variable: Build the generic implementation with TEvent type;
Returing the list ready to be injected;
Here is an extension I did to loop and build necessary types to register on DI:
public static class AssemblyExtensions
{
public static List<(Type notificationHandler, Type implementation)> GetGenericNotificationHandlerForTypesOf(this Assembly assembly,
Type AbstractClassToFilter, Type GenericUsedWithNotificationHandler, Type ImplementationType, Type NotificationHandlerGeneric)
{
List<(Type, Type)> list = new List<(Type, Type)>();
foreach (Type item in from t in assembly.GetTypes()
where !t.IsAbstract && !t.IsInterface && t.BaseType == AbstractClassToFilter
select t)
{
var genericForNotificationHandler = GenericUsedWithNotificationHandler.MakeGenericType(item);
var notificationHandler = NotificationHandlerGeneric.MakeGenericType(genericForNotificationHandler);
var implementation = ImplementationType.MakeGenericType(item);
list.Add((notificationHandler, implementation));
}
return list;
}
}
Here is how to use (please take a look in the first example to understand the code below):
var registerPairs = typeof(DomainEvent).Assembly.GetGenericNotificationHandlerForTypesOf(typeof(DomainEvent), typeof(DomainEventDispatch<>), typeof(DomainEventsDispatcher<>), typeof(INotificationHandler<>));
registerPairs.ForEach(pair => services.AddTransient(pair.notificationHandler, pair.implementation));

Registering open-generic decorators through a single binding rule

Trying to use Command/Handler pattern and Aspect Oriented Programming with Simple Injector.
I have my command and handler classes.
ICommandHandler.cs
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
MakeCoffeeCommand.cs
public class MakeCoffeeCommand
{
public string Flavor { get; set; }
}
MakeCoffeeCommandHandler.cs
internal class MakeCoffeeCommandHandler : ICommandHandler<MakeCofeeCommand>
{
public void Handle(MakeCoffeeCommand command)
{
...
}
}
MakeCakeCommand.cs
public class MakeCakeCommand
{
public float OvenTemperature { get; set; }
}
MakeCakeCommandHandler.cs
internal class MakeCakeCommandHandler : ICommandHandler<MakeCakeCommand>
{
public void Handle(MakeCakeCommand command)
{
...
}
}
So far, I can inject implementation through this single rule.
//this rule automagically ignores possibly existing decorators! :-)
c.Register(typeof(ICommandHandler<>), typeof(ICommandHandler<>).Assembly);
Then, I would like to register decorators aimed at validating the command instance. My decorator implementations depend on the concrete command types. I created an interface all the decorators have to inherit from.
ICommandHandlerValidator.cs
public interface ICommandHandlerValidator<TCommand> : ICommandHandler<TCommand>
{
}
Then, the concrete decorators.
ValidatorMakeCoffeeCommandDecorator.cs
internal class ValidatorMakeCoffeeCommandDecorator
: ICommandHandlerValidator<MakeCoffeeCommand>
{
private readonly ICommandHandler<MakeCoffeeCommand> decoratee;
public ValidatorMakeCoffeeCommandDecorator(ICommandHandler<MakeCoffeeCommand> decoratee)
{
this.decoratee = decoratee;
}
public void Handle(MakeCoffeeCommand command)
{
...
}
}
ValidatorMakeCakeCommandDecorator.cs
internal class ValidatorMakeCakeCommandDecorator
: ICommandHandlerValidator<MakeCakeCommand>
{
private readonly ICommandHandler<MakeCakeCommand> decoratee;
public ValidatorMakeCakeCommandDecorator(ICommandHandler<MakeCakeCommand> decoratee)
{
this.decoratee = decoratee;
}
public void Handle(MakeCakeCommand command)
{
...
}
}
I'm trying to register these validators with a single line, as in the previous case.
c.RegisterDecorator(typeof(ICommandHandler<>), typeof(ICommandHandlerValidator<>));
But I get this error.
The given type ICommandHandlerValidator<TCommand> is not a concrete type. Please use one of the other overloads to register this type.
It this a correct approach?
If yes, how is it possible to get rid of the error?
Note: I have to implement multiple decorators for all cross-cutting concerns. Some of them depend on the concrete command (i.e. authorization, full-text indexing), some do not, and have the same implementation shared by all the commands (i.e. logging, performance analysis).
It this a correct approach?
This answer might be a bit opinionated, but to me, this isn't the right approach. Your ICommandHandlerValidator<T> interface serves no function, and your decorators can as easily derive directly from ICommandHandler<T>.
On top of that, you are somewhat 'abusing' decorators to implement very specific logic, while decorators are best suited to implement very generic cross-cutting concerns.
Although you might argue that validation is very generic, your implementations aren't generic at all, since each decorator has logic that is specific to a single handler implementation. This leads to the situation that you get many decorators, and need to batch-register them.
What I typically like to do is to take a step back and look at the design. In your architecture you determined that business logic that mutates state is a certain artifact that deserves its own abstraction. You call this abstraction ICommandHandler<T>. Not only does this allow you to clearly distinguish these particular type of components from other components in the system, it allows you to batch register them and apply cross-cutting concerns very effectively.
While looking at your code, however, it seems to me that logic that validates commands before they are executed by their command handler has importance of its own in your application. That means it deserves an abstraction of its own. For instance, you can call it ICommandValidator<T>:
public interface ICommandValidator<TCommand>
{
IEnumerable<ValidationResult> Validate(TCommand command);
}
Note that this interface has no relationship with ICommandHandler<TCommand>. Validation components are a different artifact. The ICommandValidator<T> interface returns validation results, which can be practical for implementations. You might want to play with the best design for this validator.
Using this interface you can now define specific validators:
public class MakeCoffeeValidator : ICommandValidator<MakeCoffeeCommand> { ... }
public class MakeCakeValidator : ICommandValidator<MakeCakeCommand> { ... }
Besides the visibility of these validators in your design, this separate interface allows your validators to be batch-registered:
c.Collection.Register(typeof(ICommandValidator<>),
typeof(MakeCakeValidator).Assembly);
Here, the validators are registered as collection, assuming that there might be zero or multiple validator implementations for a single command. If there is always exactly one implementation (as you'll see with command handler implementations), you should call c.Register instead.
This by itself, however, doesn't do much, because those validators will not get executed by themselves. For this you will need to write a generic piece of cross-cutting code that can be applied to all command handlers in the system. In other words, you need to write a decorator:
public class ValidatingCommandHandlerDecorator<T> : ICommandHandler<T>
{
private readonly ICommandHandler<T> decoratee;
private readonly IEnumerable<ICommandValidator<T>> validators;
public ValidatingCommandHandlerDecorator(
IEnumerable<ICommandValidator<T>> validators,
ICommandHandler<T> decoratee)
{
this.validators = validators;
this.decoratee = decoratee;
}
public void Handle(T command)
{
var validationResults = (
from validator in this.validators
from result in validator.Validate(command)
select result)
.ToArray();
if (validationResults.Any())
{
throw new ValidationException(validationResults);
}
this.decoratee.Handle(command);
}
}
This decorator can be registered in a way you are already familair with:
c.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(ValidatingCommandHandlerDecorator<>));
Although you could try to batch-register this decorator, together with all decorators in the system, that would typically not work out great. This is because the order in which you execute cross-cutting concerns is of vital importance. For instance, when you implement a deadlock retry decorator and a transaction decorator, you wish to have the deadlock decorator to wrap the transaction decorator, otherwise you might end up retrying a deadlocked operation outside the context of a transaction (because of the way SqlTransaction and SQL server work). Likewise, you wish to operate writing the audit trail inside a transaction. Otherwise you could end up missing an audit trail for a succeeded operation.

Autofac - Resolve IRequestHandler<SpecificRequest, SpecificResponse> [duplicate]

I got an assembly with many concrete types that implement IHandler<TCommand>, such as the following:
public class MoveCustomerHandler : IHandler<MoveCustomerCommand>
{
void IHandler<MoveCustomerCommand>.Handle(MoveCustomerCommand c)
{
// some business logic for moving a customer.
}
}
Currently, I'm registering them one by one as follows:
builder.RegisterType<MoveCustomerHandler>()
.As<IHandler<MoveCustomerCommand>>();
builder.RegisterType<ProcessOrderHandler>()
.As<IHandler<ProcessOrderCommand>>();
builder.RegisterType<SomeOtherFancyHandler>()
.As<IHandler<SomeOtherFancyCommand>>();
// Many handler registrations here...
The command handlers are injected using constructor injection, as can be seen below:
public class OrderController
{
private readonly IHandler<ProcessOrderCommand> handler;
public OrderController(IHandler<ProcessOrderCommand> handler)
{
this.handler = handler;
}
}
Is there a way to batch register all my handlers in an easy way using Autofac?
In a similar style to Jim's answer but taking advantage of AsClosedTypesOf:
Assembly[] assemblies = GetYourAssemblies();
builder.RegisterAssemblyTypes(assemblies)
.AsClosedTypesOf(typeof(IHandler<>));
You probably want something like this, although I'm not sure how IsAssignable() behaves with open generics.
Assembly[] assemblies = GetYourAssemblies();
builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.IsAssignableFrom(typeof(IHandler<>)))
.AsSelf()
.AsImplementedInterfaces();

Construct generic class of concrete class from interface

I have a WCF service which accepts any entity which implements an interface. When it receives one of these entities I would like to publish an event i.e.
public void Receive(IFruit fruit)
{
messageHub.Publish(new FruitReceived<IFruit>(fruit));
}
However I would like to reify the interface so instead of everything that handles fruit subscribing to the event FruitReceived<IFruit> they can subscribe to only the type they're interested in such as FruitReceived<Apple>.
Currently I can do this through some lengthy reflection:
var fruitType = fruit.GetType();
var evt = typeof(FruitReceived<>)
.MakeGenericType(fruitType)
.GetConstructor(fruitType)
.Invoke(fruit);
This is a bit of a performance hit (even with caching the constructors) and also hard to read.
I was hoping that there's a simpler way to achieve this? I have spent so much time thinking about this solution that it's the only one I can come up with.
For reference the publish method simplifies to something like this:
public void Publish<TEvent>(TEvent evt)
{
if(_subscriptions.ContainsKey(typeof(TEvent))
{
IEnumerable<IEventHandler<TEvent>> handlers = _subscriptions[typeof(TEvent)];
foreach(var handler in handlers)
{
handler.HandleEvent(evt);
}
}
}
The underlying problem seems to be that you're receiving an instance of IFruit but downstream you want to distinguish between different concrete types.
The benefit of casting a class as an interface it implements is that consumers only need to know what the declared type is. They know it's an IFruit and that's all they need to know. As soon as they need to know more than that the benefit is reduced.
In other words, if you care at all about the difference between an Apple and an Orange then why cast it as an IFruit? Of course there are differences between implementations, but those differences - even the existence of different implementations - should be transparent to anything that depends on an IFruit.
There's no perfectly neat way to handle this. If you're not creating the generic type (as in your post) then you're doing this:
if(fruit is Apple)
There's going to be type creation or type inspection no matter what.
You could move the problem. Have a single event handler that handles FruitReceived<IFruit>. Then that event handler creates the more specific event type and re-raises it so that the more specific event handler can catch it. That way you can have event handlers specific to Apple, Orange, etc.
It's not perfect but it moves the problem from where the event is getting raised to another class that facilitates raising the more specific event type.
Another reason why this is beneficial is that your design allows for multiple event handlers. So conceivably you could raise FruitEvent<IFruit> where the concrete type is an Apple, so you want an apple-specific event handler, but you also want a generic IFruit event handler to execute. If you convert your event to FruitEvent<Apple> before raising it then you won't execute the generic event handler.
This can usually be solved with the visitor pattern. But it requires some extensive changes, starting with IFruit:
interface IFruitVisitor {
void Visit(Apple apple);
void Visit(Banana banana);
// ... you need a method for each fruit
}
interface IFruit {
Accept(IFruitVisitor visitor);
}
Then your fruits must implement that method:
class Apple : IFruit {
public void Accept(IFruitVisitor visitor) => visitor.Visit(this);
}
class Banana : IFruit {
public void Accept(IFruitVisitor visitor) => visitor.Visit(this);
}
And you can have a special visitor for your case:
class CreateFruitReceivedFruitVisitor : IFruitVisitor {
public object FruitReceived { get; private set; }
public void Visit(Banana banana) => FruitReceived = new FruitReceived<Banana>(banana);
public void Visit(Apple apple) => FruitReceived = new FruitReceived<Apple>(apple);
}
Then, just use it in your original method:
public void Receive(IFruit fruit)
{
var visitor = new CreateFruitReceivedFruitVisitor();
fruit.Accept(visitor);
messageHub.Publish(visitor.FruitReceived);
}
You need to weight in the benefits and costs of this solution. Even though it can be faster than the reflection version you showed, I believe it's much more unwieldy.

Reusable non generic method for generic methods

I have the following base interface
public interface IHandler{
void Handle(IMessage message);
}
and an generic interface inheriting the base interface
public interface IHandler<TMessage> : IHandler where TMessage : IMessage{
void Handle(TMessage message);
}
My classes can implement the interface IHandler<TMessage> mutiple times. IMessage is an base interface for messages and isn´t relevant here. Currently i´m implementing the interfaces as follows.
public class ExampleHandler : IHandler<ExampleMessage>, IHandler<OtherExampleMessag>{
void IHandler.Handle(IMessage message){
ExampleMessage example = message as ExampleMessage;
if (example != null) {
Handle(example);
}
else {
OtherExampleMessage otherExample = message as OtherExampleMessage;
if (otherExample != null) {
Handle(otherExample);
}
}
public void Handle(ExampleMessage) {
//handle message;
}
public void Handle(OtherExampleMessage) {
//handle message;
}
}
What bothers me is the way i have to implement the Handle(IMessage) method, cause in my opinion its many redundant code, and i have to extend the method each time when i implement a new IHandler<TMessage> interface on my class.
What i´m looking for is a more generic way to implement the Handle(IMessage) method (maybe in a base class for Handlers), but i´m currently stuck how to do that.
You can use the new dynamic keyword to move the overload resolution to the DLR:
void IHandler.Handle(IMessage message)
{
dynamic d = message;
Handle(d);
}
Please note that this will fail at runtime with a RuntimeBinderException if the message passed in is not valid for your class.
To avoid this exception you can add a Handler for all unknown message types:
private void Handle(object unknownMessage)
{
// Handle unknown message types here.
}
To implement IHandler.Handle in a base class, you need to do a little bit more work:
public class BaseHandler : IHandler
{
void IHandler.Handle(IMessage message)
{
dynamic d = message;
Handle(d);
}
private void Handle<TMessage>(TMessage message) where TMessage : IMessage
{
var handler = this as IHandler<TMessage>;
if(handler == null)
HandleUnknownMessage(message);
else
handler.Handle(message);
}
protected virtual void HandleUnknownMessage(IMessage unknownMessage)
{
// Handle unknown message types here.
}
}
Your specific handler would than look like this:
public class ExampleHandler : BaseHandler,
IHandler<ExampleMessage>,
IHandler<OtherExampleMessage>
{
public void Handle(ExampleMessage message)
{
// handle ExampleMessage here
}
public void Handle(OtherExampleMessage message)
{
// handle OtherExampleMessage here
}
}
This code now works like this:
The DLR calls the generic BaseHandler.Handle<TMessage> method with the real message type, i.e. TMessage will not be IMessage but the concrete message class like ExampleMessage.
In this geneirc handler method, the base class tries to case itself to a handler for the specific message.
If that is not successful, it calls HandleUnknownMessage to handle the unknown message type.
If the cast is successful, it calls the Handle method on the specific message handler, effectifly delegating the call to the concrete Handler implementation.
A reasonable way would be some judicious use of reflection:
var method = this.GetType().GetMethod("Handle", new[] { message.GetType() });
if (method != null) {
method.Invoke(this, new[] { message });
}
If you are doing this so much that performance is a problem you could cache the results of the test for a massive improvement.
You stuck because your class (in the question) does more than one thing. It deals with ExampleMessage and OtherExampleMessage. I suggest you create one class to handle one thing.
Example:
public class ExampleHandler : IHandler<ExampleMessage>
and
public class OtherExampleHandler : IHandler<OtherExampleMessag>
From my understanding, you want to have a class to handle some kind of events. In this case, you may have to use Observer pattern to notify each Handler when something happen and let they do their work.
The interfaces are saying that you have an instance that provides N services. Sure the services are similar but as they are for different types they are independent services. So your detecting a 'code smell'. The smell is 'why a common method for different services?'.
So are the services different enough to justify the generic interface declarations? The fundamental here is 'duplication'. Refactor out the duplication. Duplication is BAD. Once you move the duplicate stuff out then the answer will be self evident.
To put this another way, get rid of the common method and handle each in its own method ... the duplication is what you want to move out to another class. If so, think injection.
Love your smell detection!

Categories