Как зарегистрировать все реализации открытого универсального интерфейса с помощью Autofac
В настоящее время у меня есть интерфейс для одного шага в конвейере.
public interface IPipelineStep<T1, T2>
where T1: ModelObject
where T2: EntityObject { }
И у меня есть целый ряд шагов, которые реализуют этот интерфейс:
public class ValidateModelStep<T1, T2> : IPipelineStep<T1, T2>
where T1: ModelObject
where T2: EntityObject { }
public class Step2<T1, T2> : IPipelineStep<T1, T2>
where T1: ModelObject
where T2: EntityObject { }
public class Step3<T1, T2> : IPipelineStep<T1, T2>
where T1: ModelObject
where T2: EntityObject { }
public class Step4<T1, T2> : IPipelineStep<T1, T2>
where T1: ModelObject
where T2: EntityObject { }
В настоящее время я их регистрирую так:
builder.RegisterGeneric(typeof(ValidateModelStep<,>)).As(typeof(IPipelineStep<,>)).AsSelf();
builder.RegisterGeneric(typeof(Step2<,>)).As(typeof(IPipelineStep<,>)).AsSelf();
builder.RegisterGeneric(typeof(Step3<,>)).As(typeof(IPipelineStep<,>)).AsSelf();
builder.RegisterGeneric(typeof(Step4<,>)).As(typeof(IPipelineStep<,>)).AsSelf();
И тогда я могу использовать autofac для создания этих шагов. Проблема в том, что у меня много, много шагов. И очень неприятно, что приходится регистрировать каждый раз, когда я создаю новый.
Есть ли способ зарегистрировать их всех сразу?
Я знаю, что вы можете использовать сборку сканирования и AsClosedTypesOf
, но это не работает для открытых универсальных реализаций открытых универсальных интерфейсов.
Вещи, которые я пробовал:
builder.RegisterAssemblyTypes(myAssembly).AsClosedTypesOf(typeof(IPipelineStep<,>)).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(myAssembly).AssignableTo(typeof(IPipelineStep<,>)).As(typeof(IPipelineStep<,>)).AsSelf();
builder.RegisterAssemblyTypes(myAssembly)
.Where(t => t.IsAssignableFrom(typeof(IPipelineStep<,>)))
.As(typeof(IPipelineStep<,>)).AsSelf();
Есть ли способ использовать AsClosedTypesOf
когда реализация интерфейса также должна содержать дженерики?
заранее спасибо
2 ответа
Я полагаю, что самый простой способ - это просто отсканировать сборку самостоятельно:
foreach (var t in myAssembly.GetTypes()
.Where(c => !c.IsInterface && c.IsGenericTypeDefinition && c.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IPipelineStep<,>)))) {
builder.RegisterGeneric(t).As(typeof(IPipelineStep<,>)).AsSelf();
}
Это в основном фильтрует типы, которые являются общими и реализуют IPipelineStep<>
, затем записывается в контейнер. Я думаю, вы можете сделать то же самое с RegisterAssemblyTypes.Where(...)
Если вы предпочитаете.
Комментарий из исходного сообщения, вероятно, должен быть принятым ответом, поскольку он идеально подходит для аналогичного варианта использования.
Я хотел зарегистрировать все реализации моегоINotificationHandler<>
интерфейс. Используя регистрацию сборки Autofac, мне удалось это сделать.
builder.RegisterAssemblyTypes(assembly)
.AsClosedTypesOf(typeof(INotificationHandler<>))
.InstancePerDependency()
.PreserveExistingDefaults();
С помощьюPreserveExistingDefaults
каждый элемент добавляется вIEnumerable<INotificationHandler<T>>
и может быть решен как одним большим куском, так и независимо
using var scope = container.BeginLifetimeScope();
var handlers = scope
.Resolve<IEnumerable<INotificationHandler<T>>>()
.Select(h => h.HandleNotification(notification, cancellationToken));
Приведенный выше код разрешает все экземпляры с одним и тем же параметром универсального типа. И конкретная реализация, и первый зарегистрированный интерфейс могут и будут разрешены.