简体   繁体   中英

Resolve IEnumerable of All Types that Implement Generic Interface in Autofac

I want to be able to resolve a collection of services from Autofac that represents all registered types which implement an open generic interface.

public interface IEntityService<in T> where T : Entity
{
    void DoEntityWork(T entity);
}

I have many classes that inherit Entity and many corresponding service classes which implement IEntityService for that Entity.

public class EntityA : Entity { }
public class EntityB : Entity { }
public class EntityC : Entity { }

public class EntityAService : IEntityService<EntityA>
{
    public void DoEntityWork(EntityA entity)
}

public class EntityBService : IEntityService<EntityB>
{
    public void DoEntityWork(EntityB entity)
}

public class EntityCService : IEntityService<EntityC>
{
    public void DoEntityWork(EntityB entity)
}

Here is how I am registering them with Autofac:

builder.RegisterType<EntityAService>().As<IEntityService<EntityA>();
builder.RegisterType<EntityBService>().As<IEntityService<EntityB>();
builder.RegisterType<EntityCService>().As<IEntityService<EntityC>();

What I would like to be able to do is to resolve each one of those IEntityService registrations in a collection. However, attempting to inject them with the following code returns an empty collection:

public class MyProcessingClass(IEnumerable<IEntityService<Entity>> entityServices)
{
    _entityServices = entityServices;
}

I have tried instead registering them all As<IEntityService<Entity>>() , but this throws an ArgumentException with the following message:

The type 'MyProject.Services.EntityAService' is not assignable to service 'MyProject.Interfaces.IEntityService'1[[MyProject.Models.Entity]]

How can I resolve all of the types which implement IEntityService with a type argument that implements Entity ?

This is how contravariance works in C# works, EntityAService is not IEntityService<Entity> , this relation works another way around:

public class EntityService : IEntityService<Entity>
{
    public void DoEntityWork(Entity entity) { }
}

IEntityService<EntityA> x = new EntityService();

One way around would be introducing a non-generic version of IEntityService , registering all your entity services as that one and resolving IEnumerable<IEntityService> .

Autofac doesn't support this sort of thing out of the box. There is a ContravariantRegistrationSource but it does sort of the inverse of this - if you register IEntityService<Entity> and then resolve IEntityService<EntityA> it'll resolve the IEntityService<Entity> instance for you. It doesn't allow you to resolve IEnumerable<IEntityService<Entity>> and locate all the derived types.

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