Lifetime-управление для WinForms с AutoFac - Почему MyForm остается «живым»? - PullRequest
1 голос
/ 03 июня 2019

Я предполагаю, что в следующем сценарии мой объект Form должен быть собран GC, но он не соответствует профилировщику DotMemory.Выжившие объекты (MyView и MyPresenter и т. Д.) Перечислены в разделе «Выжившие объекты», а путь хранения ключей для MyView следующий:

  • MyForm
  • IDisposable [4]
  • Стек
  • Распределитель
  • LifetimeScope
  • Контейнер
  • MyServiceLocator
  • `2 уникальных ветви-> «Статическая ссылка» и - Объект [2040] «Дескриптор закрепления»

MyView вызывается другим Form, чей обработчик кликов обращается к MyServiceLocator свойству MyViewи объект не сохраняется Form.В результате MyView остается активным даже при выполнении другого обработчика щелчков.Однако, я не буду дублировать объекты MyView, если я прыгну между обработчиками кликов.

Это допустимый подход для WinForms с AutoFac и это ожидаемое поведение?

В принципе, я хочу иметь возможность запустить MyView через обработчик щелчков таким образом, чтобы просматривать все необходимые компонентывремя жизни зависит от вида.После того, как что-то еще щелкнуло по форме хоста, происходит удаление MyView.

Для подключения моего контейнера я использую AutofacModules и пользовательский MyServiceLocator.Остальная часть приложения использует инжектор конструктора для всех компонентов.

MyServiceLocator.cs

public class MyServiceLocator
{
    private static MyServiceLocator _instance;
    private IContainer _container;

    private MyServiceLocator()
    {
        RegisterServices();
    }

    private void RegisterServices()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<MyAutofacModule>();
        _container = builder.Build();
    }

    public static MyServiceLocator Instance => _instance ?? (_instance = new MyServiceLocator());

    public IMyView MyView
    {
        get
        {
            using (var scope = _container.BeginLifetimeScope())
            {
                return _container.Resolve<IMyView>();
            }
        }
    }
}

Регистрация формы и пользовательских элементов управления в AutofacModule.cs

public class MyAutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<MyPresenter>().As<IMyPresenter>().InstancePerLifetimeScope();
        builder.RegisterType<MyModel>().As<IMyModel>().InstancePerLifetimeScope();
        builder.RegisterType<MyUserControl>().As<IMyUserControl>().InstancePerLifetimeScope();
        builder.RegisterType<MyView>().As<IMyView>();
    }
}

1 Ответ

0 голосов
/ 04 июня 2019

Одной из причин моей проблемы, по-видимому, является отсутствие взятия аванса ILifetimeScope. Насколько я понимаю, разрешение из корневого контейнера означает, что он будет хранить ссылки на все объекты, которые он разрешил, и, следовательно, препятствует очистке GC.

Я рефакторил MyServiceLocator в это:

public class MyServiceLocator
{
    private static MyServiceLocator _instance;
    private IContainer _container;

    private ILifetimeScope _myViewLifetimeScope;

    private MyServiceLocator()
    {
        RegisterServices();
    }

    private void RegisterServices()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<MyAutofacModule>();
        _container = builder.Build();
    }

    public static MyServiceLocator Instance => _instance ?? (_instance = new MyServiceLocator());

    public IMyView MyView
    {
        get
        {
            _myViewLifetimeScope = _container.BeginLifetimeScope();
            return _myViewLifetimeScope.Resolve<IMyView>();
        }
    }

    public void EndMyViewLifetimeScope()
    {
        _myViewLifetimeScope?.Dispose();
    }
}

Однако, лучшие подходы к моей проблеме приветствуются!

...