2017-05-18 13 views
0

私はDisposeパターンについて読んできましたが、それは何か分かっています(リソースをクリーンアップしてアプリケーションにメモリがリークしないようにする)が、実用的例。IDisposableの実用的な例を書く

私の考えは、まずいくつかのリソースを使い、それらを破棄せずにコードを変更した後に、それらのリソースを適切に廃棄する単純なアプリケーションを書くことです。私が見たいのは、コードが変更される前/後のメモリ使用量で、処分がどのように役立つかを視覚化することです。

質問:どのオブジェクトを使用できますか?私はいくつかの大きな画像(JPEG画像は15 MB以上のサイズ)でやろうとしましたが、実用的な例を作ることはできません。もちろん、私は他のアイデアを公開しています。

+1

「IDisposable」を継承するものは何でも..... http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface他にも - https://www.codeproject.com/Articles/413887/Understanding-and-Implementing-IDisposable-Interfa –

+0

GCを廃棄しないと、GCはそれらのリソースを(まだ管理されていれば)クリーンアップします。良い例は、C++ DLLを呼び出すことであり、手動でメモリを割り当て、次にdisposeを使ってcleanup/freeを実行する必要があります。 – rolls

+1

通常は、管理対象外のリソースのために使用します。 – Noctis

答えて

2

この単位テストは、あなたが何を記述しているかをテストします。 Disposeを呼び出しても何も起こらないことを示すために、Disposeを呼び出しても呼び出しなくても同じことをします。

どちらの方法もファイルを作成し、ファイルを開いて書き込み、再度開いて再度書き込みます。

StreamWriterが配置されていないため、最初のメソッドはIOExceptionをスローします。ファイルは既に開いており、再度開くことはできません。

ファイルを再オープンしようとする前に2番目のファイルが破棄され、それは例外なく動作します。

[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はその理由を気にしません。それは、クリーンアップする必要があるクラス内に何かがあることを意味します。

+0

単純なWinformsアプリケーションでサンプルを実装し終えました。完璧に働き、IDisposableの目的とそれが解決する問題に関して、事柄がより明確になりました。ありがとうございました。 編集:誰かがそれを望むなら、私はコードを共有することができます。 –

1

次の例は、IDisposableインターフェイスを実装する一般的なベストプラクティスを示しています。一部のMyResouceインスタンスを作成し、Disposeメソッドを呼び出さずにテストすると、メモリリークが発生します。 MyResouceのインスタンスが終了したら、毎回Disposeを呼び出します。メモリリークはありません。 Reference

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. 
    } 
} 
関連する問題