Как обрабатывать циклические ссылки с Autofac 2.4.5?

Вики-страница autofac об круговых ссылках говорит об использовании:

cb.Register<DependsByProp>().OnActivated(ActivatedHandler.InjectUnsetProperties);

Но похоже, что ActivatedHandler больше не существует в версии 2.4.5. Покопавшись в исходниках, я нашел реализацию этого класса и вместо этого добавил реализацию метода в OnActivated. К сожалению, это все еще не работает.

Я собрал здесь минимальную репродукцию, похожую на то, что было на странице Wiki.

class M
{
    public VM VM { get; set; }

    public M()
    {
    }
}

class VM
{
    public VM(M m)
    {
    }
}

[Fact]
void CanResolveCircular()
{
    ContainerBuilder builder = new ContainerBuilder();

    builder.RegisterType<VM>();
    builder.RegisterType<M>().OnActivated(e => e.Context.InjectUnsetProperties(e.Instance));

    using (var container = builder.Build())
    {
        var m = container.Resolve<M>();
        Assert.NotNull(m);
    }
}

Этот код по-прежнему выдает исключение переполнения стека при попытке разрешения. Что мне не хватает? Как правильно заставить Autofac обрабатывать циклические зависимости?


person Ants    schedule 31.05.2011    source источник
comment
да. Я думал, что циклические зависимости означают то же, что и циклы экземпляров. В вашем ответе ниже указано, чего мне не хватало в концепциях циклических зависимостей между классами и экземплярами.   -  person Ants    schedule 31.05.2011


Ответы (2)


В документации Autofac для круговых зависимостей указано:

Обратите внимание, что нет смысла настраивать этот сценарий, если оба класса зарегистрированы в области Factory.

Обе ваши регистрации M и VM являются InstancePerDependency (ранее известными как FactoryScope), поэтому это утверждение применимо к вашему сценарию. В результате вы попадаете в бесконечный цикл создания экземпляров M и VM.

Если вы хотите, чтобы внедренное свойство VM принимало тот же экземпляр свойства M, которое вы разрешаете, вы должны изменить время жизни M на что-то отличное от InstancePerDependency (например, SingleInstance). Это показано ниже:

builder.RegisterType<M>().PropertiesAutowired(true).SingleInstance();

Примечание. Я также использую более новый метод расширения PropertiesAutowired(true). Вы можете использовать его вместо кода OnActivated в своем репродукции.

Если вам не нужен отдельный экземпляр M для каждого приложения, вы можете настроить LifetimeScope и используйте InstancePerLifetimeScope.

person bentayloruk    schedule 31.05.2011

Для всех, кто заинтересован, вот новый способ сделать это:

class DependsByProp1
{
    public DependsByProp2 Dependency { get; set; }
}

class DependsByProp2
{
    public DependsByProp1 Dependency { get; set; }
}

// ...

var cb = new ContainerBuilder();
cb.RegisterType<DependsByProp1>()
      .InstancePerLifetimeScope()
      .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);
cb.RegisterType<DependsByProp2>()
      .InstancePerLifetimeScope()
      .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);

Свойство/зависимости свойств

person MeTitus    schedule 03.05.2014