11

一部のコードを C++/CLI から C# に変換中です。C++/CLI バージョンでは、オブジェクトの 1 つにデストラクタがあります。他の一部の C++/CLI コードは、使用後にこのオブジェクトで「delete」を呼び出します。

これらの「削除」が引き続き同じように機能するようにするには、このオブジェクトの C# バージョンにどのメソッドを実装する必要がありますか?

4

4 に答える 4

17

リソースの決定論的な処分が必要な場合は、IDisposableインターフェースがあなたが探しているものだと思います。これは通常、閉じる必要があるアンマネージ ハンドル、ストリーム、またはデータベース接続などのアンマネージ リソースの場合です。

C++/CLI では、マネージド型 (ref classなど)を宣言するとIDisposable、デストラクタ構文を使用して実装され、キーワードDispose()を使用して呼び出されます。deleteそのようなマネージド型のオブジェクトをローカルで宣言すると (^または演算子を使用せずにgcnew)、C++/CLIDispose()は、オブジェクトがスコープ外になったときに自動的に呼び出します。そういう意味では、C++/CLI は C# よりも便利です。

deleteC# を使用している場合、オブジェクトを呼び出すことはできません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

于 2012-04-19T17:46:14.637 に答える
4

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 で確認します。

于 2012-04-19T18:27:54.350 に答える
1

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 が実際にファイナライザーを解放するときに呼び出されることです。ただし、ファイナライザーを自分で呼び出すことはできません (したがって、削除/破棄のタイミングが重要な場合、それは正しい解決策ではありません)。

于 2012-04-19T17:51:19.783 に答える
0

私にとっては、デストラクタが何をしているかに大きく依存します。アンマネージ リソース (SQL またはファイル接続など) の解放などを行う場合は、IDispose を実装し、Dispose() メソッドで接続を閉じます。

明示的なクリーンアップを必要としない他のオブジェクトを破棄する場合は、デストラクタを除外して GC に処理させます。

于 2012-04-19T17:47:13.760 に答える