アプリケーションを開発していると、
例外発生時に、ログやコンソールにスタックトレースを出力したいというケースは多いと思います。
言語共通でスタックトレースといえば、
一般的に例外発生時のスタックをプリントするんだな、と認識できると思います。
僕は最初に何の迷いもなく、
Exception.StackTraceを使用してログ出力していました。
試しに0除算して例外を発生させてみます。
すると↓のような出力になります。
場所 Otameshi.Form1.Calculation() 場所 {プロジェクトのパス}\Otameshi\Form1.cs:行 80 場所 Otameshi.Form1.button1_Click(Object sender, EventArgs e) 場所 {プロジェクトのパス}\Otameshi\Form1.cs:行 50
んん?何の例外??
例外のクラス名も、メッセージもわからないではありませんか。
そうです。
.netのException.StackTraceは、
本当にスタックに入れた、ソースの呼び出し履歴しか出力してくれないのです。
メソッドではなく、プロパティだからということもありますが。
JavaのException.printStackTrace()の場合、
基本的に必要な情報はすべて出してくれますが、
.netの場合そうはいきません。
ではわざわざ、.Messageや.StackTraceなどすべて取得する必要があるのか?
いいえ、ちゃんと用意されています。
.netの場合は、Exception.ToStringで
JavaのprintStackTrace相当の内容が出力できます。
ToString()での出力↓
System.DivideByZeroException: 0 で除算しようとしました。 場所 Otameshi.Form1.Calculation() 場所 {プロジェクトのパス}\Otameshi\Form1.cs:行 79 場所 Otameshi.Form1.button2_Click(Object sender, EventArgs e) 場所 {プロジェクトのパス}\Otameshi\Form1.cs:行 62
欲しかったのはこれです。
なぜ、ToStringでないと取れないのかわかりませんが、
欲しい情報は取れました。
StackTraceとToStringの違いは↓の通りです。
項目名 | StackTrace | ToString |
---|---|---|
現在の例外をスローしたクラス名 | × | ○ |
Message | × | ○ |
内部例外でのToStringの呼び出し結果 | × | ○ |
Environment.StackTraceの呼び出し結果 | ○ | ○ |
Messageはともかく、
「現在の例外をスローしたクラス名」はStackTraceに出ても良いような気がするのですがね。。。
確かにStackTraceはプロパティ、ToStringはメソッドなので、
StackTraceにMessageなどを含めるのは違う気がしますが、
「ToString」というメソッド名では、パッと見何が取れるかわかり難い気がします。
以上、StackTraceよりToString()を使用するべきの検証でした。
JavaのようにVMを介さない通常の(x86)実行環境において
「スタック上に残っている」のは「関数の呼び出し履歴」であり
例外の内容は残りません。
Exceptionクラスのインスタンスへの参照はスタック上に載っています(インスタンス(=例外の内容)はヒープ上です)が、通常変数はスタック上に載る、という仕様(というよりこれはx86プログラミング上の標準仕様)上の都合であって
「スタックトレース」といった場合「通常は呼び出し履歴を指し」ます。
よって、標準的、一般的(JavaとJava以外の他の言語、ネイティブも含めた)な考え方からすると
「スタックトレースに例外の内容が載っている」方が「不自然・非一般的な実装」と捉えるべきです。
匿名様
おっしゃる通り、スタックトレース=呼び出し履歴という解釈が本来正しいと思います。
私が未熟で例外発生時の原因調査で初めてスタックトレースという言葉を耳にしたので
「スタックトレース」=「例外に関する情報が出力されるもの」という誤った捉え方をしてしまったわけです。
ご指摘ありがとうございます、勉強になりました。