[英]Writing a practical example of IDisposable
我一直在閱讀有關Dispose模式的信息,我有點理解它的用途(清理資源,以便我的應用程序不會泄漏內存),但是我想在一個實際示例中看到它。
我的想法是編寫一個簡單的應用程序,該應用程序首先使用一些資源而不處理它們,然后在對代碼進行一些更改之后適當地處理這些資源。 我想看到的是代碼更改之前/之后的內存使用情況,以可視化處理方式。
問題:我可以使用哪些對象? 我試圖用一些大圖像(大小超過15 MB的JPEG圖像)來做,但是我無法從中建立一個實際的例子。 當然,我願意接受其他想法。
該單元測試可以完成您要描述的內容。 無論是否調用Dispose
,它都執行相同的操作,以顯示不調用Dispose
時發生的情況。
這兩種方法都會創建一個文件,打開文件,寫入文件,然后再次打開並再次寫入文件。
第一個方法拋出IOException
因為沒有處理StreamWriter
。 該文件已打開,無法再次打開。
第二個在嘗試重新打開文件之前進行了處理,並且工作正常。
[TestClass]
public class DisposableTests
{
[TestMethod]
[ExpectedException(typeof(IOException))]
public void DoesntDisposeStreamWriter()
{
var filename = CreateFile();
var fs = new StreamWriter(filename);
fs.WriteLine("World");
var fs2 = new StreamWriter(filename);
fs2.WriteLine("Doesn't work - the file is already opened.");
}
[TestMethod]
public void DisposesStreamWriter()
{
var filename = CreateFile();
var fs = new StreamWriter(filename);
fs.WriteLine("World");
fs.Dispose();
var fs2 = new StreamWriter(filename);
fs2.WriteLine("This works");
fs2.Dispose();
}
private string CreateFile()
{
var filename = Guid.NewGuid() + ".txt";
using (var fs = new StreamWriter(filename))
{
fs.WriteLine("Hello");
}
return filename;
}
}
您可能不會看到內存使用問題,因為這不是IDisposable
專門解決的問題。 所有對象都使用內存,但大多數不是一次性的。 垃圾回收器從不再引用的對象中回收內存(例如在方法中創建但在方法結束時超出范圍的對象)。
IDisposable
適用於類保留某些未進行垃圾收集的資源的情況。 另一個示例是SqlConnection
。 這與內存無關,與與SQL Server的連接有關。 只有這么多可用。 (它最終會被發布,但不是以可預見的方式發布的-這是題外話。)
類可能是IDisposable
的確切原因各不相同。 他們通常沒有共同之處。 IDisposable
不在乎原因是什么。 這只是意味着該類中的某些東西需要清理。
以下示例顯示了實現IDisposable接口的一般最佳實踐。 創建一些MyResouce
實例並在不調用Dispose
方法的情況下對其進行測試,這會導致內存泄漏。 然后,在完成MyResouce
實例后,每次都調用Dispose,不會發生內存泄漏。 參考
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.