Внедрение зависимостей .NET Core — как избавиться от экземпляров, созданных вручную?
Как и в приведенном ниже коде, я должен использовать способ регистрации factory/func с контейнером, поскольку я не знаю значение свойства «userId» заранее, но только во время выполнения. Это работает и никаких проблем с функциональными аспектами.
container.AddSingleton<IBLogic, BLogic>(); //explicitly registration 'BLogic' service object
container.AddSingleton<Func<string, IDBCache>>
(p=> (userId) => new IDBCache(userId, p.GetService<IBLogic>()));
Поскольку здесь я использую «новый IDBCache», в соответствии с инфраструктурой ссылок не удаляются службы автоматически.
Вопросы :
Сделать фреймворк для автоматического удаления сервисов, есть ли выход?
контейнер. AddSingleton <Func<string, IDBCache>> (p=> (userId) => new IDBCache(userId, p.GetService()));
Поскольку я просто регистрирую определение func/factory, а не объекта службы (например, «BLogic») как такового, дает ли AddSingleton какое-либо преимущество перед использованием «AddScoped» или «AddTransisent», как показано ниже?
container.AddTransisent<Func<string, IDBCache>>
(p=> (userId) => new IDBCache(userId, p.GetService<IBLogic>()));
1 ответ
Для этого нет простого решения. MS.DI не содержит
RegisterForDisposal
метод, который вы можете вызвать. Вам нужно будет создать отдельную оболочку, которая реализует одноразовые объекты, к которым вы можете подключить созданные вами экземпляры. Например:
services.AddSingleton<IBLogic, BLogic>();
services.AddScoped<DisposeWrapper>();
services.AddScoped<Func<string, IDBCache>>(p => (userId) =>
{
var cache = new IDBCache(userId, p.GetRequiredService<IBLogic>());
p.GetRequiredService<DisposeWrapper>().Add(cache);
return cache;
});
Где это выглядит так:
public sealed class DisposeWrapper : List<IDisposable>, IDisposable
{
public void Dispose()
{
// Dispose in reverse order as creation.
for (int i = this.Count - 1; i >= 0; i--) this[i].Dispose();
}
}
Такая реализация, однако, имеет некоторые оговорки, поскольку должна быть зарегистрирована с использованием той же области, в которой вы хотите кэшировать файлы . Вот почему в приведенном выше примере я зарегистрировал и фабрику, и фабрику как
Scoped
.
Регистрация в качестве Singleton означает, что созданные экземпляры будут удалены только после завершения работы приложения. Если вы создадите много экземпляров во время жизни приложения, это вызовет утечку памяти. Это вряд ли хорошая идея в вашем сценарии.
Регистрация обоих как временных, с другой стороны, все еще может (как ни странно) вызвать утечку памяти, потому что фабрика может быть внедрена в синглетон, вызывая его (и его
DisposeWrapper
), чтобы стать Captive Dependency.
Из-за сложностей этого дизайна я рекомендую изменить ваш дизайн.
Если вы перепроектируете таким образом, что данные времени выполнения не требуются во время создания объекта , вы можете разрешить
IDBCache
быть зарегистрированным в контейнере без фабрики (например,
AddTransient<IDBCache>()
), что позволяет нормально утилизировать его контейнером. Это удалит всю введенную выше сложность.