Можно ли удалить существующую регистрацию из конструктора контейнеров Autofac?

Что-то в этом духе:

builder.RegisterType<MyType>().As<IType>();
builder.RegisterType<MyType2>().As<IType>();
builder.DeRegisterType<MyType>().As<IType>()

var container = builder.Build();
var types = container.Resolve<IEnumerable<IType>>();
Assert.IsTrue(types.Count == 1);
Assert.IsTrue(types[0].GetType == typeof(MyType2));

Сценарий: я просматриваю кучу сборок и по ходу регистрирую типы, но хочу убедиться, что у меня есть только одна реализация данного типа. Мне нужно сделать это до того, как я создам контейнер. Я мог бы отследить это самостоятельно, но было бы неплохо, если бы Autofac мог мне немного помочь.


person Pawel Pabich    schedule 23.02.2011    source источник
comment
У меня есть еще одна причина для этого: используя RegisterAssemblyTypes, я получаю «фон» по умолчанию с InstancePerDependencyScope разрешениями. После этого я хочу обновить некоторые из них до InstancePerLifetimeScope. Это прекрасно работает, перерегистрируя их до тех пор, пока я не разрешаю перечисление некоторого интерфейса (например, того, который реализован более чем в одном классе). Удаление «фоновой» регистрации позволит это сделать.   -  person Josh Gallagher    schedule 11.05.2014
comment
Для моей конкретной проблемы я обнаружил RegisterAssemblyTypes().Except<TypeForUpgrading>() и другие плавные методы, которые могут управлять выбором и обработкой регистрируемых типов сборок.   -  person Josh Gallagher    schedule 11.05.2014


Ответы (2)


Это нельзя сделать напрямую с помощью ContainerBuilder, если только вы не начнете с нового. Имейте в виду, что сначала создав контейнер, вы сможете создать новый контейнер, отфильтровывая нежелательные типы и повторно используя регистрации из первого контейнера. Как это:

...
var container = builder.Build();

builder = new ContainerBuilder();
var components = container.ComponentRegistry.Registrations
                    .Where(cr => cr.Activator.LimitType != typeof(LifetimeScope))
                    .Where(cr => cr.Activator.LimitType != typeof(MyType));
foreach (var c in components)
{
    builder.RegisterComponent(c);
}

foreach (var source in container.ComponentRegistry.Sources)
{
    cb.RegisterSource(source);
}

container = builder.Build();

Это вряд ли очень элегантно, но это работает. А теперь, если бы вы могли уточнить, почему вы хотите это сделать, возможно, есть лучший способ.

person Peter Lillevold    schedule 23.02.2011
comment
Умная идея. Вам также потребуется скопировать свойство RegistrationSources, но это сработает. - person Nicholas Blumhardt; 24.02.2011
comment
@Nicholas - там добавлено копирование исходников. Кроме того, не уверен, какие последствия это имело, но в итоге я получил дубликаты компонента LifetimeScope. Так что фильтровать и это тоже. - person Peter Lillevold; 24.02.2011
comment
@ Николас Блюмхардт, не могли бы вы объяснить, зачем нам это нужно? функция регистрации/разрешения работает без второго foreach - person monstr; 24.08.2017
comment
Есть ли в этом ошибка? Что такое 'c' в строке foreach (источник var в c.ComponentRegistry.Sources) - person Damien Sawyer; 08.06.2018
comment
@NicholasBlumhardt Я столкнулся с этим вопросом в поисках решения проблемы, с которой я столкнулся с декораторами (см.: stackoverflow.com/questions/52611948/). Замена регистраций, вероятно, не является ответом, но это тот случай, когда это может пригодиться. Лучшим решением в моем случае было бы, если бы регистрации декораторов переопределяли существующие регистрации, как и другие компоненты. - person Derek Greer; 02.10.2018

У Питера Л., вероятно, самый простой вариант.

Чтобы полностью обойти эту проблему, можете ли вы изменить способ обнаружения компонентов, чтобы фильтровать их перед регистрацией? Кажется, что должен быть подход, который обходит это... Также может возникнуть проблема в дальнейшем, чтобы решить, какие компоненты оставить, а какие удалить.

Более сложный подход — переопределить поддержку IEnumerable, чтобы отфильтровать то, что вам не нужно. т.е. скопируйте и измените этот код, чтобы создать FilteredCollectionSource, исключающий ненужные компоненты.

var elements = c.ComponentRegistry.RegistrationsFor(elementTypeService);

станет:

var elements = c.ComponentRegistry.RegistrationsFor(elementTypeService)
    .Where(reg => /* not a duplicate */);

Если вы добавите свой FilteredCollectionSource в билдер с помощью RegisterSource(), он будет использоваться вместо встроенного.

person Nicholas Blumhardt    schedule 24.02.2011
comment
К сожалению, я получаю компоненты партиями, и количество партий неизвестно. Спасибо за помощь - person Pawel Pabich; 24.02.2011