Вы можете очень красиво инкапсулировать метод @ Danielg , чтобы позволить Autofac внедрить список типов в конструктор. Это требует от вас реализации IRegistrationSource
.
В моем случае я хотел получить все зарегистрированные типы, полученные из IConsoleCommand
, например:
public Help(TypeList<IConsoleCommand> commands)
{
_commands = commands;
}
Я использовал простой DTO-List для переноса типов и T
, для которого я хотел разрешить их:
public class TypeList<T> : List<Type>
{
public TypeList(IEnumerable<Type> types) : base(types)
{
}
}
Фактический источник регистрации реализован следующим образом, где <T>
из TypeList<T>
используется для соответствия типу интерфейса, который зарегистрирован и который мы хотим получить.
internal class TypeListSource<T> : IRegistrationSource
{
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
if (service is IServiceWithType swt && typeof(TypeList<T>).IsAssignableFrom(swt.ServiceType))
{
var registration =
new ComponentRegistration(
id: Guid.NewGuid(),
activator: new DelegateActivator(swt.ServiceType, (context, p) =>
{
var types =
context
.ComponentRegistry
.RegistrationsFor(new TypedService(typeof(T)))
.Select(r => r.Activator)
.OfType<ReflectionActivator>()
.Select(activator => activator.LimitType);
return new TypeList<T>(types);
}),
services: new[] {service},
lifetime: new CurrentScopeLifetime(),
sharing: InstanceSharing.None,
ownership: InstanceOwnership.OwnedByLifetimeScope,
metadata: new Dictionary<string, object>()
);
return new IComponentRegistration[] {registration};
}
// It's not a request for the base handler type, so skip it.
else
{
return Enumerable.Empty<IComponentRegistration>();
}
}
public bool IsAdapterForIndividualComponents => false;
}
Наконец, вы должны добавить его к builder
с помощью:
builder.RegisterSource(new TypeListSource<IConsoleCommand>());
Теперь Autofac может разрешать типы с помощью внедрения зависимостей.