.NET核心如何处理手动创建的实例



与下面的代码一样,我必须使用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";,根据链接框架不自动处理服务。

问题

  1. 要让框架自动处理服务,有什么办法吗?

  2. 集装箱AddSingleton<Func<字符串,IDBCache>gt;(p=>(userId(=>新IDBCache(userId,p.GetService(((;

由于我只是注册func/factory的定义,而不是服务对象(如"BLogic"(本身,因此AddSingleton与下面的"AddScoped"或"AddTransisent"相比有什么优势吗?

container.AddTransisent<Func<string, IDBCache>>
(p=> (userId) => new IDBCache(userId, p.GetService<IBLogic>()));

没有简单的解决方法。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;
});

DisposeWrapper如下所示:

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();
}
}

然而,这样的实现附带了一些注意事项,因为DisposeWrapper应该使用与缓存IDBCache相同的作用域进行注册。这就是为什么在上面的示例中,我将DisposeWrapper和工厂都注册为Scoped

DisposeWrapper注册为Singleton意味着创建的IDBCache实例只有在应用程序结束时才会被释放。如果在应用程序的生存期内创建了许多IDBCache实例,则会导致内存泄漏。在你的情况下,这不太可能是个好主意。

另一方面,将两者注册为瞬态仍然可能(令人困惑(导致内存泄漏,因为工厂可能被注入到单例中,导致它(及其DisposeWrapper(成为Captive依赖项。

由于这种设计的复杂性,我建议您更改设计。

如果重新设计IDBCache,使得在对象构建过程中不需要运行时数据,则可以允许IDBCache在容器中注册,而无需工厂(例如AddTransient<IDBCache>()(,从而允许容器正常处理它。这将消除上述所有引入的复杂性。

最新更新