c# - 例外処理 - 集約例外ハンドラ
WPFアプリケーションで例外をグローバルにキャッチしますか? (4)
「VBのエラー時に次回レジュームしますか? それは恐ろしいもののように聞こえる。 最初のお勧めはしません。 二番目の勧告はそれをしないで、それについて考えないでください。 あなたはあなたの欠陥をよりよく分離する必要があります。 この問題にどのようにアプローチするかについては、コードがどのように構造化されているかによって異なります。 MVCなどのパターンを使用している場合、これはあまり難しいことではありませんし、グローバル例外を必要としません。 第二に、log4netのような良いログライブラリを探すか、トレースを使う。 私たちは、あなたが話している例外の種類や、アプリケーションのどの部分が例外をスローするかといった詳細を知る必要があります。
WPFアプリケーションの一部で実行時に例外がスローされることがあります。 私はグローバルにすべての未処理の例外をキャッチしてログに記録したいが、何も起こらなかったかのようにプログラムの実行を続行する(VBのOn Error Resume Next
)。
これはC#で可能ですか? もしそうなら、どこに例外処理コードを置く必要がありますか?
現在、 try
/ catch
ラップすることができ、発生する可能性のあるすべての例外をキャッチする単一のポイントは表示されません。 そしてそれでも、捕まえてしまったために何が実行されたのかは残してしまいました。 それとも、私はひどく間違った方向に考えていますか?
ETA:以下の多くの人々が指摘しているように、このアプリケーションは原子力発電所の制御用ではありません。 クラッシュした場合、それほど大きな問題ではありませんが、主にUIに関連するランダム例外は、それが使用されるコンテキストでは迷惑です。 プラグインのアーキテクチャーを使用しているため、他の人も同様に拡張されている可能性があります(その場合は学生でもありますので、エラーのないコードを書くことができる経験豊富な開発者はいません )。
捕捉される例外については、完全なスタックトレースを含むログファイルにログを記録します。 それがその運動の全体的なポイントでした。 ちょうどVBのOERNに私のアナロジーを取っていた人々にも、文字通り言えばそれに反しています。
私は、盲目的に特定のクラスのエラーを無視するのは危険であり、アプリケーションのインスタンスを破損する可能性があることを知っています。 これまで述べたように、このプログラムは誰にとってもミッションクリティカルではありません。 彼らの正しい気持ちで誰もそれに人間文明の生存を賭けないでしょう。 それは単に特定の設計アプローチをテストするための小さなツールです。 ソフトウェア工学。
アプリケーションをすぐに使用するために、例外で発生する可能性のあることはあまりありません。
- 例外処理なし - エラーダイアログとアプリケーション終了。 実験は繰り返される必要がありますが、おそらく別の科目で繰り返されます。 エラーは記録されませんが、残念です。
- 一般的な例外処理 - 良質なエラーがトラップされ、害はありません。 これは開発中に見られたすべてのエラーから判断される一般的なケースでなければなりません。 この種のエラーを無視するとすぐには結果は得られません。 コアデータ構造は十分にテストされているので、簡単にこれを生き残ることができます。
- 一般的な例外処理 - 深刻なエラーがトラップされ、おそらく後でクラッシュする可能性があります。 これはめったに起こりません。 これまで見たことはありません。 とにかくエラーがログに記録され、クラッシュが発生することが避けられません。 これは概念的には非常に最初の場合に似ています。 我々はスタックトレースを持っていることを除いて。 そして、大部分の場合、ユーザーは気づかないことさえあります。
プログラムによって生成された実験データについては、重大なエラーは最悪の場合、データが記録されないだけである。 実験の結果をそれほど変わらない微妙な変化はほとんどありません。 その場合でも、結果が疑わしいと思われる場合はエラーがログに記録されます。 全体的な外れ値であれば、そのデータポイントを捨てることができます。
要約すると:はい、私は自分自身を少なくとも部分的には身体的にはまだまだだと思っています。プログラムを実行している大域的な例外処理ルーチンは、まったく悪いものではありません。 これまでに2回述べたように、このような決定はアプリケーションによっては有効かもしれません。 この場合、それは有効な決定であって、完全で完全なものではないと判断された。 他のアプリケーションの場合、決定は異なるように見えるかもしれません。 しかし、私が間違いを無視しているという理由だけで、このプロジェクトで働いていた私や他の人々が潜在的に世界を爆破すると非難してはいけません。
サイドノート:そのアプリケーションにはちょうど1人のユーザーしかいません。 これは、WindowsやOfficeのようなものではなく、何百万人も使用されています。例外が発生した場合のコストは、ユーザーにとってはまったく異なっています。
Application.DispatcherUnhandledException Event
使用しApplication.DispatcherUnhandledException Event
。 要約については、 この質問を参照してください( Drew Noakesの答えを参照)。
スタックオーバフロー、メモリ不足、データベースへの保存中にネットワーク接続が失われた場合など、アプリケーションの再開を妨げる例外が残っていることに注意してください。
AppDomainのすべてのスレッド 、 UIディスパッチャスレッド 、および非同期関数からスローされた例外をキャッチするNLogを使用するコード例:
App.xaml.cs:
public partial class App : Application
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
SetupExceptionHandling();
}
private void SetupExceptionHandling()
{
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
LogUnhandledException((Exception)e.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");
DispatcherUnhandledException += (s, e) =>
LogUnhandledException(e.Exception, "Application.Current.DispatcherUnhandledException");
TaskScheduler.UnobservedTaskException += (s, e) =>
LogUnhandledException(e.Exception, "TaskScheduler.UnobservedTaskException");
}
private void LogUnhandledException(Exception exception, string source)
{
string message = $"Unhandled exception ({source})";
try
{
System.Reflection.AssemblyName assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
message = string.Format("Unhandled exception in {0} v{1}", assemblyName.Name, assemblyName.Version);
}
catch (Exception ex)
{
_logger.Error(ex, "Exception in LogUnhandledException");
}
finally
{
_logger.Error(exception, message);
}
}
ここにNLog
を使った完全な例がありNLog
using NLog;
using System;
using System.Windows;
namespace MyApp
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private static Logger logger = LogManager.GetCurrentClassLogger();
public App()
{
var currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = (Exception)e.ExceptionObject;
logger.Error("UnhandledException caught : " + ex.Message);
logger.Error("UnhandledException StackTrace : " + ex.StackTrace);
logger.Fatal("Runtime terminating: {0}", e.IsTerminating);
}
}
}