簡體   English   中英

autofac解析所有類型的開放泛型類型?

[英]autofac Resolve all types of open generic type?

我猜測沒有辦法像Autofac那樣做以下內容,為ctor注入一個可枚舉的開放泛型類型集合? 各種Handle類型都有依賴關系,否則我只是動態構建它們。

    class EventOne : IEvent {...}
    class EventTwo : IEvent {...}
    class EventThree : IEvent {...}
    interface IHandleEvent<T> where T : IEvent {...}
    class HandleEventOne : IHandleEvent<EventOne> {...}
    class HandleEventTwo : IHandleEvent<EventTwo> {...}
    class HandleEventThree : IHandleEvent<EventThree> {...}

    builder.RegisterAssemblyTypes(myAssembies).AsClosedTypesOf(typeof(IHandleEvent<>));
    builder.RegisterType<AService>().As<IAService>();


    class AService : IAService
    {
      public AService(IEnumerable<IHandleEvent<IEvent>> handles)
      {...}
    }

正如評論中所解釋的那樣,你想要的東西是不可能在C#中實現的並且有充分的理由。 如果您能夠將IHandleEvent<EventOne>轉換為IHandleEvent<IEvent> ,它將允許傳遞EventTwo ,這將在運行時失敗。

所以你需要的是一個中介抽象,它允許獲得所有兼容的事件處理程序並調用它們。 這樣的中介通常稱為IEventPublisher ,可能如下所示:

public interface IEventPublisher {
    void Publish(IEvent e);
}

您現在可以創建特定於容器的實現。 例如,對於Autofac,這將如下所示:

public class AutofacEventPublisher : IEventPublisher {
    private readonly IComponentContext container;

    public AutofacBusinessRuleValidator(IComponentContext container) {
        this.container = container;
    }

    public void Publish(IEvent e) {
        foreach (dynamic handler in this.GetHandlers(e.GetType())) {
            handler.Handle((dynamic)e);
        }
    }

    private IEnumerable GetHandlers(Type eventType) =>
        (IEnumerable)this.container.Resolve(
            typeof(IEnumerable<>).MakeGenericType(
                typeof(IHandleEvent<>).MakeGenericType(eventType)));
}

消費者現在可以依賴這種新的抽象:

class AService : IAService
{
    public AService(IEventPublisher publisher) {...}
}

您將無法將IHandleEvent<EventThree>IHandleEvent<IEvent>因為IHandleEvent<T>不是協變,您可以通過添加out修飾符來添加它。

public interface IHandleEvent<out TEvent> 
    where TEvent : IEvent
{ }

不幸的是, Autofac不支持協變類型,只支持逆變類型。 順便說一句,您可以創建自定義IRegistrationSource實現以獲得所請求的行為。 像這樣的東西:

public class CovariantHandleEventRegistrationSource : IRegistrationSource
{
  public bool IsAdapterForIndividualComponents
  {
    get
    {
      return false;
    }
  }

  public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, 
                                Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
  {
    IServiceWithType typedService = service as IServiceWithType;
    if (typedService == null)
    {
      yield break;
    }

    if (typedService.ServiceType.IsGenericType && typedService.ServiceType.GetGenericTypeDefinition() == typeof(IHandleEvent<>))
    {
      IEnumerable<IComponentRegistration> eventRegistrations = registrationAccessor(new TypedService(typeof(IEvent)));

      foreach (IComponentRegistration eventRegistration in eventRegistrations)
      {
        Type handleEventType = typeof(IHandleEvent<>).MakeGenericType(eventRegistration.Activator.LimitType);
        IComponentRegistration handleEventRegistration = RegistrationBuilder.ForDelegate((c, p) => c.Resolve(handleEventType, p))
                                          .As(service)
                                          .CreateRegistration();

        yield return handleEventRegistration;
      }
    }
  }
}

使用此IRegistrationSource您可以擁有:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<EventOne>().As<IEvent>();
builder.RegisterType<EventTwo>().As<IEvent>();
builder.RegisterType<EventThree>().As<IEvent>();
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
        .AsClosedTypesOf(typeof(IHandleEvent<>));

builder.RegisterSource(new CovariantHandleEventRegistrationSource());

IContainer container = builder.Build();

var x = container.Resolve<IEnumerable<IHandleEvent<IEvent>>>();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM