実行時にその一部が例外をスローするWPFアプリケーションがあります。未処理の例外をグローバルにキャッチしてログに記録しますが、それ以外の場合はプログラムの実行を継続します(VBのOn Error Resume Next
など)。
これはC#で可能ですか?もしそうなら、例外処理コードを正確にどこに置く必要がありますか?
現在、try
/catch
をラップして、発生する可能性のあるすべての例外をキャッチできる単一のポイントはありません。そして、それでもキャッチのために実行されたものは何でも残していたでしょう。または、ここで恐ろしく間違った方向に考えていますか?
ETA:以下の多くの人が指摘しているため、このアプリケーションは原子力発電所を制御するためのものではありません。それがクラッシュする場合、それはそれほど大したことではありませんが、主にUI関連のランダムな例外は、それが使用されるコンテキストで迷惑です。プラグインアーキテクチャを使用し、他のユーザー(その場合は学生も使用可能です。したがって、no完全にエラーのないコードを書くことができる経験豊富な開発者)。
キャッチされる例外については、完全なスタックトレースを含め、ログファイルに記録します。それがその演習の全体のポイントでした。 VBのOERNに文字通りあまりにも私の類似性を取っている人々に対抗するためだけに。
特定のクラスのエラーを盲目的に無視することは危険であり、アプリケーションインスタンスが破損する可能性があることを知っています。前述のように、このプログラムは誰にとってもミッションクリティカルではありません。彼らの正しい心の誰も、それに人間の文明の生存を賭けないでしょう。これは、特定の設計アプローチをテストするための単なる小さなツールです。ソフトウェア工学。
アプリケーションをすぐに使用する場合、例外で発生する可能性のあるものは多くありません。
プログラムによって生成された実験データに関して:深刻なエラーは最悪の場合、データが記録されないだけです。実験の結果をわずかに変更する微妙な変更はほとんどありません。その場合でも、結果が疑わしい場合は、エラーがログに記録されました。全体の外れ値であれば、そのデータポイントを捨てることができます。
要約すると、はい、私は自分自身を少なくとも部分的に正気であると考えています。また、プログラムを必ずしも完全に悪とするグローバルな例外処理ルーチンを考えていません。前述のように、そのような決定は、アプリケーションに応じて有効な場合があります。この場合、それは完全で全くのでたらめではなく、有効な決定であると判断されました。 他のアプリケーションでは、決定が異なるように見えるかもしれません。しかし、エラーを無視しているという理由だけで、私やそのプロジェクトに携わった他の人が世界を爆破する可能性があると非難しないでください。
サイドノート:そのアプリケーションには1人のユーザーがいます。 WindowsやOfficeのように、例外をユーザーにバブルさせるコストがそもそも非常に異なっている何百万人もの人々によって使用されるものではありません。
Application.DispatcherUnhandledException Event
を使用します。概要については この質問 を参照してください( Drew Noakesの回答 を参照)。
データベースへの保存中にスタックオーバーフロー、メモリ不足、ネットワーク接続の喪失などが発生した場合、アプリケーションを正常に再開できないという例外がまだあることに注意してください。
NLogを使用して、AppDomain内のすべてのスレッド、Iディスパッチャスレッド、およびasyncからスローされた例外をキャッチするサンプルコード関数:
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);
}
}
AppDomain.UnhandledException イベント
このイベントは、キャッチされなかった例外の通知を提供します。これにより、システムのデフォルトハンドラーがユーザーに例外を報告し、アプリケーションを終了する前に、アプリケーションが例外に関する情報を記録できます。
public App()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
}
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception) args.ExceptionObject;
Console.WriteLine("MyHandler caught : " + e.Message);
Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
}
UnhandledExceptionイベントがデフォルトのアプリケーションドメインで処理される場合、どのアプリケーションドメインでスレッドが開始されたかに関係なく、スレッドの未処理の例外に対してそこで発生します。そのアプリケーションドメインでイベントが発生します。そのアプリケーションドメインが既定のアプリケーションドメインではなく、既定のアプリケーションドメインにもイベントハンドラーがある場合、イベントは両方のアプリケーションドメインで発生します。
たとえば、スレッドがアプリケーションドメイン "AD1"で開始し、アプリケーションドメイン "AD2"のメソッドを呼び出し、そこから例外をスローするアプリケーションドメイン "AD3"のメソッドを呼び出すとします。 UnhandledExceptionイベントを発生させることができる最初のアプリケーションドメインは「AD1」です。そのアプリケーションドメインが既定のアプリケーションドメインでない場合、イベントは既定のアプリケーションドメインでも発生する可能性があります。
さらに、他の人がここで言及したことは、Application.DispatcherUnhandledException
(およびその similars )と
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1" />
</runtime>
</configuration>
app.config
で、セカンダリスレッドの例外がアプリケーションをシャットダウンするのを防ぎます。
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);
}
}
}