3

IDisposableを実装するオブジェクトを破棄するための一般的なメソッドを作成しようとしています。DisposeObject()

元の参照が指すオブジェクトを破棄していることを確認するために、オブジェクトを参照渡ししようとしています。

しかし、私は言うコンパイルエラーが発生しています

'ref' 引数の型がパラメーターの型と一致しません

以下の (簡略化された) コードでは、 と の両方がIDisposable_Baz_Bar実装しています。

代替テキスト

質問は、

  1. このエラーが発生するのはなぜですか?
  2. それを回避する方法はありますか?

[更新] これまでに提供された回答から、IDisposable引数をnullに設定しない限り、を使用せずに値でオブジェクトを渡すことができますrefnullメソッド内で使い捨てオブジェクトを設定するかどうかについて、別の問題が発生していますDisposeObject

完全を期すための完全なソースは次のとおりです。

public class Foo : IDisposable
{
    private Bar _Bar;
    private Baz _Baz;
    private bool _IsDisposed;

    ~Foo() { Dispose(false); }

    public void Dispose(bool disposing)
    {
        if (!_IsDisposed)
        {
            if (disposing)
            {
                DisposeObject(ref _Baz);
                DisposeObject(ref _Bar);
            }
        }

        _IsDisposed = true;
    }

    private void DisposeObject(ref IDisposable obj)
    {
        try
        {
            if (obj == null) 
                return;
            obj.Dispose();
            obj = null;
        } catch (ObjectDisposedException) { /* Already Disposed... */ }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

public class Bar : IDisposable
{
    public void Dispose() {}
}

public class Baz : IDisposable
{
    public void Dispose() {}
}

[結果]
内の 引数を null( obj = null;) にするコードを削除したDisposeObject ので、最終的なコードになりました。

    public void Dispose(bool disposing)
    {
        if (!_IsDisposed)
        {
            if (disposing)
            {
                DisposeObject(_Baz);
                DisposeObject(_Bar);
            }
        }

        _IsDisposed = true;
    }

    private void DisposeObject(IDisposable obj)
    {
        try
        {
            if (obj == null) 
                return;
            obj.Dispose();
        } catch (ObjectDisposedException) { /* Already Disposed... */ }
    }
4

5 に答える 5

7

あなたの例のオプションは次のとおりです(現在、コンパイラに対して検証することはできませんが、アイデアは得られます):

private void DisposeObject<T>(ref T obj) where T : IDisposable
{
    // same implementation
}

それを呼び出すには、使用します

DisposeObject<Baz>(ref _Baz);
DisposeObject<Bar>(ref _Bar);

他のコメントで指摘されているように、発生するコンパイラ エラーには独自の目的があります (メソッド内で他のタイプの IDisposable を割り当てることを防ぎ、一貫性のない状態につながります)。

于 2009-04-27T16:24:21.950 に答える
4

これを試して:

IDisposable d = (IDisposable)_Baz;
DisposeObject(ref d);

編集:Adamが指摘しているように、コードではこれを参照する必要はありません。オブジェクトは常に参照として渡されます。

于 2009-04-27T15:50:40.640 に答える
4

参照型を渡すので、参照で渡す必要はありません。refメソッド定義からキーワードを削除する必要があります。これを行うと、問題は発生しないはずですが、これが単に呼び出すよりも効果的または明確であるかどうかはわかりDispose()ません(明示的な実装のためにキャストする必要がなく、これが次のnullチェックを行うという事実を除いて)君)。

編集

ダンス、このトピックを取り巻く議論があなたに役立つことを願っていますが、あなたの本来の意図は実行可能なものではないようです。として何かを渡すために、パラメーターが期待するrefもの以外の型を持つ変数を渡すことはできません(つまり、パラメーターがの場合に実装する、またはその他として宣言された変数を渡すことはできません)。パラメータを使用すると、割り当てを呼び出し元に戻すことができるため、互換性のない型を変数に格納できる可能性があります。refclassinterfaceIDisposablerefIDisposableref

ここでの最善の策は、それがnull必要な場合は自分自身を割り当てることです。チェックをカプセル化し、null例外を無視して問題のrefない関数にしたいが、このシナリオでは、どのようにスライスしても機能しない場合は、残念ながら。

于 2009-04-27T15:55:18.337 に答える
2

このアプローチは変なにおいがしますが、今はそれを無視します。

問題を解決するには、渡すオブジェクトを「(IDisposable)」でキャストする必要があります

私はコンパイラーとジョン・スキートの意志を認めます。これには実際のオブジェクトが必要です。

IDisposable _BazD = (IDisposable)_Baz;
DisposeObject(ref _BazD);

また、try / catchに加えて、DisposeObject()にnullチェックを追加します。「obj==null」は、同じオブジェクトに対して複数回ヒットした場合の高価な例外キャッチと比較すると、すばやく簡単にチェックできます。 うーん...それは1分前に​​ありましたか?どうでも。

于 2009-04-27T15:51:09.347 に答える
0

Dan C に感謝します。コメントを追加するのに十分な担当者がまだいないため、これを回答として追加する必要があります。ただし、このソリューションについては、Dan C の功績によるものです。

これは作業コードです:

public override void Dispose()
{
    base.Dispose();

    DisposeOf<UserTableAdapter>(ref userAdapter);
    DisposeOf<ProductsTableAdapter>(ref productsAdapter);

    if (connection != null)
    {
        if (connection.State == ConnectionState.Open)
        {
            connection.Close();
        }
        DisposeOf<SqlConnection>(ref connection);
    }
}

private void DisposeOf<T>(ref T objectToDispose) where T : IDisposable
{
    if (objectToDispose != null)
    {
        objectToDispose.Dispose();
        objectToDispose = default(T);
    }
}
于 2010-05-13T19:42:41.387 に答える