3

みなさん、おはよう、

ここで少し言語理論の質問があります... C# の例外処理とデリゲートが場合によっては異なる動作をすることを示唆する参考文献をオンラインで見つけましたが、この問題に関する具体的なドキュメントは見つかりません。

最近、Microsoft Excel アドインのデリゲート内で例外が発生し、MSVC ランタイムでハード クラッシュが発生するという大きな問題が発生しました。デリゲートを削除することでこれは解決しましたが、私は今、悲惨な詳細を知りたいと思っています.

コアコードの簡潔な例として:

Delegate del; // initialized elsewhere
try
{
    del.DynamicInvoke();
}
catch(Exception e)
{
    /* Parsing of exception to generate user-friendly message here */
}

上記の構成により、集中型のエラー処理が可能になり、純粋なコードの観点からは、クリーンで簡潔になりました。公開されている各関数はデリゲートとして宣言され、上記のフラグメントを介して実行されます。

単純なコンソール アプリでは、デリゲートから例外をスローするか、単純な予期しないエラー (たとえば、null ポインターで ToString() を "誤って" 呼び出す) をスローすると、期待どおりに機能し、エラーは必要に応じて処理されます。

MS Excel を投入すると、ハード クラッシュが発生します。コードをステップ実行すると、エラーが発生した場所が示されますが、すべてが破壊の大きな火の玉になる前に、スタックの巻き戻しが行われていないように見えます。

私の仮説は、.NET ランタイム (つまり、コード) をホストしている COM が、通常の .NET コードの実行とは異なることを行っているというものです。これによりエンドポイントが強制終了され、Excel はこれを認識せず、COM を介してエンドポイントにアクセスしようとしますが、エンドポイントが何らかの形で消失したことを確認し、Excel が代わりにクラップアウトします。

これは、Excel + COM + デリゲートの組み合わせでのみ発生しますが、この動作でどちらがより影響力があるかは正直わかりません... 何か考えはありますか?

4

4 に答える 4

1

ここでわかることは、例外がスローされたときに暗黙的に作成している MS Excel COM オブジェクトを解放していないということです。私の経験では、MS Office アプリはリソースが解放されないことに非常に敏感です (ただし、私の経験のほとんどは Outlook での経験です)。

可能であれば、この方法で COM ベースの例外を処理しようとしない傾向があります。集中ログが必要な場合は、代わりに Application.ThreadException (WinForms アプリの場合) と AppDomain.CurrentDomain.UnhandledException を参照してください。

関数内で、メソッドの finally {} ブロックで Marshal.ReleaseComObject() を呼び出して、例外がスローされたときに Excel が停止しないようにすることができます。

于 2008-10-19T17:36:09.440 に答える
0

私が感じる理由の1つは、デリゲートが別のスレッドで例外をスローしている実際のコードを呼び出しているという事実によるものです。したがって、非同期呼び出しが実行される前に現在のスレッド関数がほとんど終了するため、非同期と呼ばれる別のスレッドの例外は現在のスレッドではキャッチされません。

于 2009-02-16T13:45:55.407 に答える
0

補足: 例外キャッチの全体的な考え方は、それらを「飲み込んで」エラー メッセージを表示することではなく、可能であれば状況から回復し、リソースをクリーンアップすることです。

必要な場所 (つまり、スローされる可能性のあるコードの周り) で try/catch を使用し、共通関数を呼び出して問題を表示/ログに記録することをお勧めします。

また、異なるスレッドを使用して Excel COM オブジェクトにアクセスすると、多くの奇妙なことが起こる可能性があります。

あなたの質問に適切に答えるには、より多くの情報が必要です:

  1. それはいつも起こりますか?
  2. そうでない場合、問題が発生した場合、それはマネージ例外ですか、それとも Excel オブジェクトからスローされたものですか?
  3. 例外をスローするだけの単純なメソッドを作成できますか (新しい ApplicationException(); をスロー)、まだ問題があるかどうかを確認できますか?

乾杯

于 2008-10-17T19:34:24.803 に答える
0

返事が遅くなってすみません - 忙しい週です!

例外キャッチの全体的な考え方は、それらを「飲み込んで」エラーメッセージを表示することではなく、可能であれば状況から回復し、リソースをクリーンアップすることです。

ええ、それがアイデアですが、実際には、常にきれいに機能するとは限りません。ここで問題となっているコードは本質的に仲介者であり、多くの場合、エラーが発生するかどうかを知ることができず、エラーが発生した場合、ユーザーが実際に何をしようとしているのかを知ることができないため、自動的に回復します。

それはいつも起こりますか?

はい、予期しない例外であり、常に C#/.NET コード内で発生した .NET として表示される場合

例外をスローするだけの単純なメソッドを作成し (新しい ApplicationException(); をスロー)、まだ問題があるかどうかを確認します。

いいえ、独自の例外をスローすると、毎回正常に機能します。ハード クラッシュが発生するのは、ランタイム自体が例外を生成した場合のみです。

例外がスローされたときに暗黙的に作成している MS Excel COM オブジェクトを解放していない

これはもっともらしい。VBA レイヤーは、COM を介して Excel から .NET にデータを渡すため、リソースの所有権に関して奇妙なことを行っている可能性があります。

集中ログが必要な場合は、代わりに Application.ThreadException (WinForms アプリの場合) と AppDomain.CurrentDomain.UnhandledException を参照してください。

前者は調べませんでしたが、後者は呼び出されませんでした。私の最初の試みの 1 つは、何らかの理由でデリゲート ベースの例外がネットをすり抜けたと仮定して、AppDomain レベルでそれをキャッチすることでした。

Marshal.ReleaseComObject() を呼び出すことができます

興味深いことに、私はその機能を知りませんでした。私たちは明示的な COM コードをほとんど無視し、最小限のものを使用して、.NET CLR がその魔法を発揮することを願っています (!)。

デリゲートを削除することで回避しましたが、すべてが満足しているようです。将来のOffice + VBA + COM + CLRコードでデリゲートと例外に注意する(または完全に回避する)ことを覚えておく必要があります:-)

于 2008-10-21T12:35:36.237 に答える