一部のコードを C++/CLI から C# に変換中です。C++/CLI バージョンでは、オブジェクトの 1 つにデストラクタがあります。他の一部の C++/CLI コードは、使用後にこのオブジェクトで「delete」を呼び出します。
これらの「削除」が引き続き同じように機能するようにするには、このオブジェクトの C# バージョンにどのメソッドを実装する必要がありますか?
リソースの決定論的な処分が必要な場合は、IDisposable
インターフェースがあなたが探しているものだと思います。これは通常、閉じる必要があるアンマネージ ハンドル、ストリーム、またはデータベース接続などのアンマネージ リソースの場合です。
C++/CLI では、マネージド型 (ref class
など)を宣言するとIDisposable
、デストラクタ構文を使用して実装され、キーワードDispose()
を使用して呼び出されます。delete
そのようなマネージド型のオブジェクトをローカルで宣言すると (^
または演算子を使用せずにgcnew
)、C++/CLIDispose()
は、オブジェクトがスコープ外になったときに自動的に呼び出します。そういう意味では、C++/CLI は C# よりも便利です。
delete
C# を使用している場合、オブジェクトを呼び出すことはできませんDispose()
。代わりに手動で呼び出す必要があります。IDisposable
オブジェクトを破棄するもう 1 つの方法は、using
ブロックです。
ファイナライザー (デストラクタ構文を使用して C# で実装される) は、いつ呼び出されるかが決定論的ではないため、C++ デストラクタと同じではありません。ファイナライザーを持つオブジェクトは、基本的に、ファイナライザー スレッドがファイナライザーを呼び出すことを決定するまでキューに入れられるため、それがいつ呼び出されるかを正確に知ることは事実上ありません。
管理されていないリソースを処理するための最善の方法は、おそらく 2 つの組み合わせです。推奨されるアプローチについては、http:
//msdn.microsoft.com/en-us/library/b1yfkh5e (v=vs.100).aspx を参照してください。
ただし、 を使用する場合IDisposable
は、管理されていないリソースを決定論的に破棄できますが、管理対象オブジェクトはガベージ コレクタによって (非決定論的に) 収集する必要があります。
C++/CLI と C# の違いを説明する記事を見つけました。興味深いかもしれません:
http://weblogs.thinktecture.com/cnagel/2006/04/ccli-finalize-and-dispose.html
C++/CLI と C# の間には用語の不一致があります。C++/CLI デストラクタ (~Foo) は IDisposable.Dispose() メソッドの実装です。C++/CLI クラスは IDisposable を明示的に実装していません。デストラクタが存在するだけで自動的に実装されます。
C++/CLI ファイナライザー (!Foo) は C# デストラクターです。
したがって、C++/CLI の削除演算子は、Dispose() メソッドを呼び出すことと同じです。^ ハットのない参照型のローカル変数によってトリガーされる、C++/CLI のスタック セマンティクスに注意してください。コンパイラは、スコープ ブロックの最後に Dispose() への隠し呼び出しを生成します。これは、C# のusingキーワードと同等です。ソース コードからはわかりにくいので、細心の注意を払うか、生成された IL を ildasm.exe で確認します。
C# は同じツールを提供しませんが、パターンを提供します。dtor がストリームを閉じたり、ポインターのリンクを解除したり、状態を適切に設定したりする場合は、IDisposable
インターフェイスが適切であると感じます。
// C#
void Dispose()
{
_stream.Close();
_ptr = null;
_running = false;
}
// with
obj.Dispose();
GCにメモリを開いたままにすることはできません。解放できるものと解放すべきものを GC が認識できるようにする方法があります。詳細については、http://msdn.microsoft.com/en-us/library/ee787088.aspxを参照してください。
usingでは、メソッドを適切IDisposable
に呼び出す必要があることに注意してください。Dispose()
したがって、 each の代わりにdelete
、 を使用しますDispose()
。ファイナライザーの安全な部分は、GC が実際にファイナライザーを解放するときに呼び出されることです。ただし、ファイナライザーを自分で呼び出すことはできません (したがって、削除/破棄のタイミングが重要な場合、それは正しい解決策ではありません)。
私にとっては、デストラクタが何をしているかに大きく依存します。アンマネージ リソース (SQL またはファイル接続など) の解放などを行う場合は、IDispose を実装し、Dispose() メソッドで接続を閉じます。
明示的なクリーンアップを必要としない他のオブジェクトを破棄する場合は、デストラクタを除外して GC に処理させます。