1

I am working on handling domain events on save by adding them to a List on our Entities.

public abstract class Entity
{
   public List<IDomainEvent> DomainEvents;
   // code truncated
}

my interface for IDomainEvent and Handlers are as follows:

public interface IDomainEvent
{
}
public interface Handles<T> where T : IDomainEvent
{
   void Handle(T args);
}

This should enable me to get the list of handler that can handle that event such as AssignActionPlanToCustomer

public class AssignActionPlanToCustomer: Handles<ActionPlanCreatedForCustomer>
{
   // code truncated 
}
public IEnumerable<Handles<T>> Handlers<T>(T domainEvent) where T : IDomainEvent
{
    var actualType = typeof(Handles<>).MakeGenericType(domainEvent.GetType());
    foreach (var i in _serviceProvider.GetServices(actualType))
    {
        yield return (Handles<T>)i;
    }
}

The problem is that

  1. If I don't convert the generic type to the specific type, I get nothing from my _serviceProvider i.e. Service Provider cannot find Handles<IDomainEvent>
  2. If I do get the specific type, the return type of GetServices(type) is a generic IEnumerable<object?> that cannot be cast to the generic IEnumerable<Handles<IDomainEvent>>
  3. If I try to return it as a dynamic type, the runtime cannot find the correct constructor.

There has to be an easier way to handle either the service provider, or the casting of the specific event to the more general event. What am I missing here?

currently I am able to work around it by doing the following:

public interface Handles<out T> where T : IDomainEvent
{
   void Handle(IDomainEvent args);
}

This works, except I have to manually cast the IDomainEvent to the derived class inside of each handler. It's a bit annoying, but it does work.

  • `Handles` must be contravariant over `T`. Invariance is the default meaning that `Handles` is not a subtype of `Handles` just because `Derived` is a subtype of `Base` – Aluan Haddad Jul 13 '21 at 02:12
  • Does this answer your question? [Generic Variance in C# 4.0](https://stackoverflow.com/questions/2208043/generic-variance-in-c-sharp-4-0) – Aluan Haddad Jul 13 '21 at 02:17
  • So, if I make it `Handles`, I still cannot find a way to get it to Handle the derived type properly. Is there another way to force it to the correct type? For instance casting it like `(Handles)object` Or making a generic type or something? – Taylor Hall Jul 14 '21 at 16:16
  • Why wouldn't you just write `return _serviceProvider.GetServices(typeof(object?)).OfType>();` where in `Handles` is `interface Handles { void Handle(T event); }`? – Aluan Haddad Jul 14 '21 at 17:58
  • Same issue. If the interface is `interface Handles{ void Handle(T event)}`, I cannot produce a generic list of events. If I get the event directly, it works; but once I put the event into a `List`, then the Service Provider looks for `Handles` or if I cast it to the derived type, then it looks correctly for `Handles` however, this is not convertible back to `Handles` or `Handles` `Handles` is null, and `Handles` is an illegal cast. – Taylor Hall Jul 15 '21 at 16:51

0 Answers0