5

今日、私はファイルで操作を実行したかったので、このコードを思いつきました

    class Test1
    {
        Test1()
        {
            using (var fileStream = new FileStream("c:\\test.txt", FileMode.Open))
            {
                //just use this filestream in a using Statement and release it after use. 
            }
        }
    }

しかし、コード レビューで、IDisposable インターフェイスと Finalizer メソッドの実装を求められました。

    class Test : IDisposable
    {
        Test()
        {
            //using some un managed resources like files or database connections.
        }

        ~Test()
        {
            //since .NET garbage collector, does not call Dispose method, i call in Finalize method since .net garbage collector calls this
        }

        public void Dispose()
        {
            //release my files or database connections
        }
    }

しかし、私の質問は、なぜ私がしなければならないのですか?

私の方法論を正当化することはできませんが、usingステートメント自体がリソースを解放できる場合にIDisposableを使用する必要があるのはなぜですか)

何か特定の利点がありますか、それとも何か不足していますか?

4

6 に答える 6

8

メソッドのスコープ内でのみリソースを使用するため、例では using ステートメントが正しいです。例えば:

Test1()
{
    using (FileStream fs = new FileStream("c:\\test.txt", FileMode.Open))
    {
        byte[] bufer = new byte[256];
        fs.Read(bufer, 0, 256);
    }
}

ただし、リソースが 1 つのメソッドの外で使用される場合は、Dispose メソッドを作成する必要があります。このコードは間違っています:

class Test1
{
    FileStream fs;
    Test1()
    {
        using (var fileStream = new FileStream("c:\\test.txt", FileMode.Open))
        {
            fs = fileStream;
        }
    }

    public SomeMethod()
    {
        byte[] bufer = new byte[256];
        fs.Read(bufer, 0, 256);
    }
}

IDisposable正しいことは、ファイルが使用後に解放されるように実装することです。

class Test1 : IDisposable
{
    FileStream fs;
    Test1()
    {
        fs = new FileStream("c:\\test.txt", FileMode.Open);
    }

    public SomeMethod()
    {
        byte[] bufer = new byte[256];
        fs.Read(bufer, 0, 256);
    }

    public void Dispose()
    {
        if(fs != null)
        {
            fs.Dispose();
            fs = null;
        }
    }
}
于 2013-09-02T07:28:45.853 に答える
5

IDisposableあなたが提供した情報に基づいて、実装またはファイナライザを実装する理由はまったくありませんTest

アンマネージ リソース (ウィンドウ ハンドル、GDI ハンドル、ファイル ハンドル) を解放するファイナライザーのみを実装します。Win32 API などを PInvoking しない限り、通常はこれを行う必要はありません。ファイル ハンドルについて心配FileStreamする必要はありません。

ファイナライザーは、オブジェクトがガベージ コレクションされるときにアンマネージ リソースをクリーンアップすることを目的としています。

ガベージ コレクターがオブジェクトの収集を決定するまでに非常に長い時間がかかる可能性があるため、クリーンアップをトリガーする方法が必要になる場合があります。いいえ、それは正しい方法でGC.Collect()はありません。;)

ガベージ コレクタを待たずにネイティブ リソースを早期にクリーンアップできるようにするIDisposableには、クラスに実装します。これにより、呼び出し元は GC を待たずにクリーンアップをトリガーできます。これにより、オブジェクトが GC によって解放されることはありません。ネイティブ リソースを解放するだけです。

オブジェクトが Disposable である別のオブジェクトを所有している場合、所有しているオブジェクトも実装IDisposableし、単に他のオブジェクトの を呼び出す必要がありますDispose()

例:

class Apple : IDisposable
{
    HWND Core;

    ~Apple() { Free(); }
    Free()
    {
        if(Core != null)
        {
            CloseHandle(Core); 
            Core = null;
        }
    }
    Dispose() { Free(); }
}

class Tree : IDisposable
{
    List<Apple> Apples;
    Dispose()
    {
        foreach(var apple in Apples)
            apple.Dispose();
    }
}

Treeファイナライザがないことに注意してください。クリーンアップDisposeを気にする必要があるため、実装します。リソースを確実にクリーンアップするためのファイナライザーがあります。呼び出しによる早期クリーンアップを可能にしますAppleAppleCoreAppleDispose()

Disposeファイナライザーが不要であり、確実に不要である理由は、クラスがTest管理されていないメンバー フィールドまたはIDisposable. 使い捨ての をたまたま作成しましたFileStreamが、メソッドを終了する前にそれをクリーンアップします。Testオブジェクトによって所有されていません。

この場合には、例外が 1 つあります。他の人に継承されることがわかっているクラスを作成していて、他の人が を実装IDisposableする必要がある場合は、先に進んで を実装する必要がありますIDisposable。そうしないと、呼び出し元はオブジェクトを破棄することを知りません (または、キャストせずに破棄することさえできません)。ただし、これはコードの匂いです。通常、クラスから継承して追加することはありませんIDisposable。もしそうなら、それはおそらく設計が悪いです。

于 2013-09-03T17:14:08.690 に答える
5

ブロックはインターフェースusingを実装するクラスにしか使用できないという「No One」の答えは正しいですし、その説明も完璧です。IDisposableあなたの側からの質問は、「なぜ IDisposable を Test クラスに追加する必要があるのに、コード レビューで、Test クラスに IDisposable インターフェイスと Finalizer メソッドを実装するように求められた」というものです。
答えは簡単です
。1) 非常に多くの開発者が従うコーディング標準に従って、IDisposable何らかのリソースを使用するクラスに実装することは常に良いことであり、そのオブジェクトのスコープが超えたら、そのクラスの Dispose メソッドがすべてを確実にします。リソースが解放されました。
2) 作成されたクラスは、将来変更が行われないようなものではなく、そのような変更が行われ、新しいリソースが追加された場合、開発者は Dispose 関数でそれらのリソースを解放する必要があることを知っています。

于 2013-09-02T07:54:38.003 に答える
2

IDisposable を使用する理由

簡単な答えは、IDisposable を実装していないクラスは using では使用できないということです。

using ステートメント自体がリソースを解放できる場合

いいえ、リソース自体を解放することはできません。

上で書いたように、using を使用できるようにするには、IDisposable を実装する必要があります。ここで、IDisposable を実装すると、Dispose メソッドが取得されます。このメソッドでは、オブジェクトが不要になったときに破棄する必要があるすべてのリソースを処理する必要があるすべてのコードを記述します。

USING の目的は、オブジェクトがスコープ外に出たときに dispose メソッドを呼び出すことです。

 using(SomeClass c = new SomeClass())
 { }

に変換されます

 try
 {
     SomeClass c = new SomeClass();
 }
 finally
 {
     c.Dispose();
 }
于 2013-09-02T07:09:42.517 に答える