C# 在自定义类中实现实体框架的IDisposable

C# 在自定义类中实现实体框架的IDisposable,c#,entity-framework-6,idisposable,C#,Entity Framework 6,Idisposable,我使用实体框架,比如 public sealed class CacheManagementHelper { private readonly GJobEntities db = new GJobEntities(); public List<User> GetUsers() { return db.Users.ToList(); } } 公共密封类CacheManagementHelper { 私有只读GJobEntities db=新

我使用实体框架,比如

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

   public List<User> GetUsers()
   { 
       return db.Users.ToList();
   }
}
公共密封类CacheManagementHelper
{
私有只读GJobEntities db=新GJobEntities();
公共列表GetUsers()
{ 
返回db.Users.ToList();
}
}
VisualStudio2019女士建议如下

警告CA1001在“CacheManagementHelper”上实现IDisposable 因为它会创建以下IDisposable类型的成员: “身体”。如果“CacheManagementHelper”以前已发布, 将实现IDisposable的新成员添加到此类型是不允许的 被认为是对现有消费者的突破性改变

我在这里找到了一些线索

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

谢谢你的帮助

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

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

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

一般来说,处置的责任在于创造者。所以,如果您创建了它,您将对其进行处置

这就是@swdon评论的来源


我在他的代码中看到的最大问题是db是公共的。我不知道是谁正确地处理了这些问题伦敦时间19年8月2日7:07

这就是为什么不应该有公共的非只读IDisposable成员字段。因为:当调用方覆盖它时,您没有简单的方法来跟踪它,那么谁负责调用
Dispose


不,你不应该 国际奥委会 因此,您可能需要使用一个。国际奥委会框架的作用是:;它接管了创建对象的责任,因此,它还负责处理对象。注意: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;
}
如果使用此方法,则不必在此处实现
idispassable
,因为您不是自己创建对象的,您只需从框架请求上下文,并让它调用
Dispose
方法即可

我为什么要提到这一点?因为这是默认的

那么用这个办法,

不,您不应该实现IDisposable,因为您没有创建IDisposable(但是您应该放弃DbContext创建)


是的,你应该 可识别 如果您需要坚持当前的模式(这很有意义),您应该实现
IDisposable
。通过创建IDisPassable成员,您负责处理这些成员。您可以通过实现
IDisposable
将其委托给类的创建者

public sealed class CacheManagementHelper : IDisposable
该对象的创建者现在创建IDisposable对象,并负责处理该对象

//keeping it local
public List<User> GetUsers()
{ 
    using (var db = new GJobEntities())
        return db.Users.ToList();
}
您唯一的工作是正确实现接口并配置资源

不过,通过阅读文档来正确地实现它还是很不错的。我建议您使用此实现:

那么用这个办法,

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


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

//keeping it local
public List<User> GetUsers()
{ 
    using (var db = new GJobEntities())
        return db.Users.ToList();
}
//将其保留在本地
公共列表GetUsers()
{ 
使用(var db=new GJobEntities())
返回db.Users.ToList();
}
那么用这个办法,

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


错误的方法 如果您阅读了“”,您就会知道,如果正确地实现了它,您将非常安全地防范内存泄漏

因此,有人可能会争辩说,您不需要同时调用
Dispose
,因为垃圾收集器将为您执行此操作

这是一种误解

它的问题如下:

  • 1) 您不知道正在调用的组件是否正确实现。如果不进行处置(如果使用未经管理的内存),它可能会泄漏
  • 2) 内存泄漏是;与时间有关。令人惊讶的hé?请这样看:当您重新启动系统或重新启动应用程序时,内存又回来了。这不是永久性的。从以前开始,这与应用程序的生命周期有关。但是,多线程、无服务器编码等方面的发展确实要求我们对它的看法略有不同。泄漏可能在特定时间范围内发生。一个很好的例子是高内存消耗的图像处理或耗尽连接池
所以,没有办法知道垃圾收集器什么时候过来清理东西。它可能不够快,无法在以下方面产生问题:打开的连接计数、图形资源等。您正在泄漏,并且依赖垃圾收集器修复您的混乱,这是一种错误的方法



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

您必须通过实现
IDisposable
接口,为您的类的消费者提供处理内部
db
上下文的可能性:

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

   public List<User> GetUsers()
   { 
       return db.Users.ToList();
   }

   public void Dispose()
   { 
       db.Dispose();          
   }
}
公共密封类CacheManagementHelper:IDisposable
{
私有只读GJobEntities db=新GJobEntities();
公共列表GetUser