12

アンマネージ リソースに対して SafeHandle を内部的に使用するサード パーティ ライブラリがあります。一部のエラーの場合、オブジェクトを破棄して再作成する必要があります。ただし、dispose の実装にはバグがあり、これらのケースのサブセットでハンドルを閉じることができません。これにより、ファイナライザーが実行されるまで、新しいオブジェクトが正常に作成されなくなります。

サードパーティのコードが修正されるまで、これに対処するために 2 つの解決策 (どちらも悪) が提案されています。

  1. a を実行しGC.Collectてファイナライザーを実行し、オブジェクトをクリーンアップします

  2. リフレクションを使用してハンドルを取得し、破棄に失敗した場合はハンドルを閉じます

これらのうち、悪意が少ないのはどれですか?その理由は? これらのいずれかよりも害が少ないと考えられていない他の方法はありますか?

4

5 に答える 5

14

私は個人的な反省に賛成です。これはローカライズされたバグなので、解決策もローカルにする必要があります。そして、コードが何をしようとしているのかがより明確になります。また、バグが修正されたときに通知するいくつかのテストを追加することもできます。そのため、不要になったハックは簡単に削除できます。

...
thirdPartyObject.Dispose();
ThirdPartyDisposeBugWorkaround(thirdPartyObject);
...

void ThirdPartyDisposeBugWorkaround(ThirdPartyClass thirdPartyObject)
{
   //Do private reflection here
}

一方、GC を強制すると、グローバルな効果があります。そして、GC に干渉する理由はたくさんあります (ほとんどは悪いことです)。あなたのコードが何をするかは、それほど明白ではありません。そのため、バグが修正された後でも通話が維持される場合があります。

古い新しいもの: グローバルな状態を使用してローカルの問題を管理しないでください

于 2011-05-21T14:49:23.573 に答える
5

私はリフレクションを使用しますが、何が問題なのかを明示的に明確にするエラー処理があることを確認してください。エラーが発生するのは数年後になる可能性があり、開発チームがひっくり返って誰もこの奇抜なハックを覚えていない可能性があることを念頭に置いてください。 .

try
{
   .. hacky reflection ..
}
catch(Exception ex)
{
    throw new Exception("Reflection on private field 'Xyz' of 3rd Party Component 'Abc' failed.  Was 'Abc' updated? Reflection is used due to bug in 'Dispose' implementation.", ex);
}
于 2011-05-21T14:50:31.250 に答える
3

最初に機能するものを選択します。どちらも機能する場合は、システムへの影響が最も少ない方を選択してください。Gc.Collect は、アプリケーション全体でハンマーのようなものです。リフレクション コードは脆弱ですが、影響は非常に小さいはずです。

于 2011-05-21T15:03:07.240 に答える
2

それが封印されているとマークされていない場合は、それを継承して独自の破棄を実装できます。リフレクションと GC については、間違いなくリフレクションを使用します。他の人が言ったように、GC は期待どおりに動作しない可能性があります。コレクションの反復を実行できますが、実際にハンドルを解放することはできません。

注意したいのは、この SafeHandle への参照がまだ他の何かにある場合、それを解放すると、システムに他のバグが簡単に持ち込まれる可能性があるということです。

于 2011-05-21T14:54:33.140 に答える
0

「CodeInChaos」引数を前に進めて、特定の世代でコレクションを呼び出さないのはなぜですか。

GC.GetGeneration(Object obj)オブジェクトが存在する世代と を返しますGC.Collect(Int32 gen)

元:

Int32 generation = GC.GetGeneration(theObject);
theObject = null;
GC.Collect(generation);
GC.WaitForPendingFinalizers();
GC.Collect(generation); // this is req because first collect puts thisObject on freachable queue not // garbaged yet.
于 2011-05-21T15:07:41.623 に答える