【发布时间】:2021-03-02 21:57:43
【问题描述】:
我正在调查我的应用程序中的内存泄漏。这是上下文:
假设我必须处理不同类型的 XMLs 文件并且我每天收到大量的 XML 文件,所以我有一个IXmlProcessor 接口。
public interface IXmlProcessor
{
void ProcessXml(string xml);
}
还有一些具体的 XMLProcessors。
public class UserXmlProcessor : IXmlProcessor
{
private readonly IUserRepository _userRepository;
public UserXmlProcessor(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void ProcessXml(string xml)
{
// do something with the xml
// call _userRepository
}
}
所有IXmlProcessor 具体类型都注册到 DI 容器,为了解决它们,我有一个 Factory 类,它也注册到 DI 容器,如下所示:
public class XmlProcessorFactory where TType : class
{
private readonly IServiceProvider _serviceProvider;
public XmlProcessorFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IXmlProcessor GetImplementation(string identifier)
{
var type = FindType(identifier);
return _serviceProvider.GetService(type) as IXmlProcessor;
}
private Type FindType(string identifier)
{
// do some reflection to find the type based on the identifier (UserXmlProcessor, for example)
// don't worry, there's caching to avoid unecessary reflection
}
}
在某些时候我把它们都称为:
public class WorkItem
{
public string Identifier { get; set; }
public string Xml { get; set; }
}
public class WorkingClass
{
private readonly XmlProcessorFactory _xmlProcessorFactory;
public WorkingClass(XmlProcessorFactory xmlProcessorFactory)
{
_xmlProcessorFactory = xmlProcessorFactory;
}
public void DoWork(WorkItem item)
{
var processor = _xmlProcessorFactory.GetImplementation(item.Identifier);
processor.ProcessXml(item.Xml);
}
}
IUserRepository 是一个简单的实现,带有实体框架上下文。
所以,问题出在这里:根据微软documentation:
从容器解析的服务绝不应该由开发人员处理。
通过 DI 接收 IDisposable 依赖项不需要接收者自己实现 IDisposable。 IDisposable 依赖项的接收者不应对该依赖项调用 Dispose。
因此,如果我将 IUserRepository 注入控制器,那很好,容器将处理对象的处置以及 EF 上下文的处置,不需要 IDisposable。
但是我的 Xml 处理器呢?文档说:
不是由服务容器创建的服务
开发者负责处置服务。
避免使用服务定位器模式。例如,当您可以使用 DI 代替时,不要调用 GetService 来获取服务实例。 另一个需要避免的服务定位器变体是注入一个在运行时解决依赖关系的工厂。这两种做法都混合了控制反转策略。
还有_ = serviceProvider.GetRequiredService<ExampleDisposable>(); 是一种反模式。但正如您所见,我确实需要在运行时根据 XML 标识符解决依赖关系,我不想求助于 switch case。
所以:
- IXmlProcessors 是否应该实现 IDisposable 并手动释放 IUserRepository?
- 我是否也应该级联并让 IUserRepository 实现 IDisposable 以释放 EntityContext?
- 如果是这样,如果将其注入控制器中,这不会影响服务生命周期吗?
【问题讨论】:
标签: c# .net .net-core dependency-injection idisposable