我即将构建我的第一个n层Web应用程序,因此,我在教育自己的原则,并查看示例代码。我在这里遇到了这种类型的应用程序的一个很好的例子:https://github.com/MarlabsInc/SocialGoal 但是,我对如何处理数据层上的EF上下文感到困惑。到目前为止,我已经处理了我的上下文,例如,通过使用using块,或者覆盖我的MVC控制器上的Dispose方法。但是,在此应用程序中,从不显式调用Dispose方法,而是实例化上下文的工厂类派生自实现IDisposable的基类:
工厂类:
public class DatabaseFactory : Disposable, IDatabaseFactory
{
private SocialGoalEntities dataContext;
public SocialGoalEntities Get()
{
return dataContext ?? (dataContext = new SocialGoalEntities());
}
protected override void DisposeCore()
{
if (dataContext != null)
dataContext.Dispose();
}
}
一次性课程:
public class Disposable : IDisposable
{
private bool isDisposed;
~Disposable()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore()
{
}
}
有了新手的眼睛,看起来上下文永远不会被处理掉。调用Dispose(bool)
的唯一方法是终结器。由于这会将false
作为参数传递,因此永远不会调用虚拟DisposeCore()
方法,并且由于必须调用Context以进行处置,因此它永远不会被调用。我是否正确地思考这个问题,或者错过了一些关键的.NET知识?
答案 0 :(得分:2)
此无参数Dispose()
方法是IDisposable
接口的经典实现,并且在Disposable
基类上正确完成:
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
Dispose()
将在任何using-block结束时调用,随后将调用Dispose(true)
和DisposeCore()
,这可能会在派生类中实现以清理托管资源。
这不是一段特别好的代码
首先,这就是应该如何实施dispose-pattern:
public class MyDisposableThing : IDisposable
{
public MyDisposableThing()
{
// Constructor
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Dispose managed resources
}
// Dispose unmanaged resources
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~MyDisposableThing()
{
Dispose(false);
}
}
可以通过两种方式销毁此类型的实例:
在第一种情况下,您希望发布托管资源 - 这就是您调用Dispose()
的原因。在第二种情况下,您不必这样做,因为根据定义,它们是受管理的,GC应该像处理您自己的对象一样处理它们。您总是希望清理非托管资源。这就是disposing
标志与相关if
- 语句一起存在的原因。
对GC.SuppressFinalize()
的调用是一种优化 - 它告诉垃圾收集器该实例已被Dispose()
清除,并且无需再次调用其终结符~MyDisposableThing()
。 / p>
最后,请注意Dispose(bool disposing)
是virtual
,这非常重要。引入需要在处理期间处理的新资源的派生类现在可以覆盖它,并且在释放自己的资源(托管或非托管)之后,他们可以调用base.Dispose(disposing)
public class MyDerivedDisposableThing : MyDisposableThing
{
public MyDerivedDisposableThing()
{
// Constructor
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Dispose managed resources
}
// Dispose unmanaged resources
// Call base class
base.Dispose(disposing);
}
}
将此与您的代码段对比
首先,DisposeCore()
没有参数,也不会从终结器调用(因为disposing
将为false),因此阻止派生类利用整个模式并清理非托管资源。
其次,isDisposed
是私有的,这使得它在基类上完全没有必要和无用,因为基类非常原始。
<强>意见强>
根本不要创建基础Disposable
类。只需正确实现Dispose
模式,如本答案以及MSDN
http://msdn.microsoft.com/en-us/library/fs2xkftw(v=vs.110).aspx
这有点不合适,但最好做得恰到好处。
答案 1 :(得分:0)
垃圾收集器无论如何都要清理或释放您的托管对象/资源。仅当您急需释放这些资源(例如图像)时,才需要为托管对象或资源进行处置。如果框架没有在工厂调用Dispose方法,那么只有您可以决定何时调用该Dispose方法(可能在某些事件上,例如,关闭一个特定的选项卡。)。那么你确定,你不再需要这些资源,处理它们会释放内存。