在自定义类中为实体框架实现 IDisposable

Dev*_*per 5 c# idisposable entity-framework-6

我使用实体框架

public sealed class CacheManagementHelper 
{
   private readonly GJobEntities db = new GJobEntities();

   public List<User> GetUsers()
   { 
       return db.Users.ToList();
   }
}
Run Code Online (Sandbox Code Playgroud)

并且 MS Visual Studio 2019 建议遵循

警告 CA1001 在“CacheManagementHelper”上实现 IDisposable,因为它创建了以下 IDisposable 类型的成员:“GJobEntities”。如果 'CacheManagementHelper' 之前已发布,则向此类型添加实现 IDisposable 的新成员被视为对现有使用者的重大更改。

我在这里找到了一些线索

实体框架和调用 context.dispose()

但目前还不清楚我是否有实施IDisposable

感谢帮助!

Ste*_*fan 5

但目前还不清楚我是否已经实现了 IDisposable。

这是一个棘手的问题,有几个答案:

  • 不,你不应该。
  • 是的你应该。
  • 不,你不必。

一般而言: IDisposable对象应在其生命周期结束时处理。关于框架是否为您处理这个问题存在一些争论,但这是一种错误的方法。(在底部,在错误方法下,我将添加原因)

一般而言,处置的责任在于创建者。所以; 如果你创建它,你就处置它

这是@swdon 评论的来源;

我在他的代码中看到的最大问题是 db 是公开的。我不知道谁负责正确摆脱。– swdon 2019 年 8 月 2 日 7:07

这基本上就是为什么您不应该拥有公共非只读 IDisposable 成员字段的原因。因为:当呼叫者覆盖它时,您将没有简单的方法来跟踪它,然后谁负责呼叫Dispose


不,你不应该

国际奥委会

因此,您可能想要使用像 Unity 这样IoC 框架。这个 IoC 框架的作用是;它接管了创建对象的责任,因此,它也负责处理对象。请注意:IoC 框架的目的不是成为工厂,它只是副作用之一。

因此,使用 IoC,您不会自己创建成员,而是请求它。它可能看起来像这样:

private GJobEntities _context;

//constructor: this object can also be created by the IoC framework.
public CacheManagementHelper (GJobEntities context)
{
    //set your field here
    _context = context;
}
Run Code Online (Sandbox Code Playgroud)

如果你使用它,你不必IDispossable在这里实现,因为你不是自己创建对象,你只需从框架请求上下文并让它调用Dispose方法。

我为什么要提到这个?因为它是 .net 未来的默认设置。

所以,使用这种方法;

不,你不应该实现 IDisposable,因为你没有创建 IDisposables,(但你应该摆脱 DbContext 创建)。


是的你应该

一次性使用

如果你需要坚持你当前的模式——这是有道理的——你应该实现IDisposable. 通过创建 IDispossable 成员,您负责处置它们。您可以通过实现将其委托给类的创建者IDisposable

public sealed class CacheManagementHelper : IDisposable
Run Code Online (Sandbox Code Playgroud)

此对象的创建者现在创建 IDisposable 对象,因此负责处理它。

您唯一的工作是正确实现接口并处理您的资源。

通过阅读文档正确实现它是很好的。我建议您使用此实现:正确使用 IDisposable 接口

所以,使用这种方法;

是的,您应该实施 IDisposable 并清理您的资源。


不,你不必

或者,

您可以在调用函数时创建上下文,将其保留在本地并将其处理在那里。这样你就不需要实现了IDisposable,因为上下文的创建者也在处理它。

//keeping it local
public List<User> GetUsers()
{ 
    using (var db = new GJobEntities())
        return db.Users.ToList();
}
Run Code Online (Sandbox Code Playgroud)

所以,使用这种方法;

不,您不必实现 IDisposable,因为您没有创建 IDisposable 成员字段。


错误的做法

如果您阅读了“正确使用 IDisposable 接口”,您就会知道,如果正确实现,您就可以非常安全地防止内存泄漏。

因此,有人可能会争辩说您不需要一起调用Dispose所有内容,因为垃圾收集器会为您完成。

这是一种误解。

它的问题在于:

  • 1) 你不知道你调用的组件是否正确实现。如果没有被处理,它可能会泄漏(如果使用无人管理的内存)。
  • 2)内存泄漏是;时间相关。令人惊讶吗?像这样看:当您重新启动系统或重新启动应用程序时,内存又回来了。它不是永久性的。从过去开始,这与应用程序生命周期有关。但是关于多线程、无服务器编码等方面的发展确实需要我们稍微不同地看待它。泄漏可能在特定时间范围内相关。一个很好的例子是高内存消耗图像处理或耗尽连接池。

所以,没有办法知道垃圾收集器什么时候来清理东西。它可能不够快以产生以下问题:打开连接计数、图形资源等。您正在泄漏,并依靠垃圾收集器来修复您的混乱,这是一种错误的方法。


最后一句话: EF DbContext 通过跟踪您的所有更改(它基本上是一个工作单元)在其生命周期内收集了大量资源。随着时间的推移,保持长期存在的 DbContext 可能会导致性能下降。所以,请注意这一点。