- PR -

ArgumentException,ArgumentNullExceptionでパラメータ名とメッセージを入力したときメッセージだけ取り出

投稿者投稿内容
もとべえ
会議室デビュー日: 2004/09/17
投稿数: 16
投稿日時: 2005-07-01 13:40
引用:

NAL-6295さんの書き込みより:

そういう意味ではないです。
想定外の例外は上まで潰さないで一番上でcatchしてあげれば良いという考えです。



確かにエラーによってはそういう対処方法も必要かと思います。ためになりますね。
File.Existsについては私も存じています。

エンドユーザからみるとプロパティのセットの時もチェックするときもファイルが無ければ「ファイルがみつかりません。」と発生することを想定して組んでいます。これはそれぞれの状況とかもあるかと思いますが、私の場合は同じエラーなのに、発生する箇所によってエラー内容が違うと言うことをなるべくないようにしています。しかも少し前にチェックしたところではダイアログ表示で、それより後は不正なエラーが発生しました。と表示するのではちょっと・・・。
私はFile.Existsで失敗したら例外FileNotFoundExceptionを自分で出すようにします。

そしてそのクラスを使用したものがcatchしてコメントを出すようにします。
もとべえ
会議室デビュー日: 2004/09/17
投稿数: 16
投稿日時: 2005-07-01 13:45
引用:

きくちゃんさんの書き込み (2005-07-01 13:13) より:
#どっかで書いたような気もしますが…。

.NET の場合、例外は、開発者に対して異常を伝えるための機構だと考えています。
ですから、エンドユーザが直接扱うようなアプリケーションでは、基本的に例外を発生させないようにプログラミングすべきであって、それに頼るような書き方をしちゃぁ、いけないんじゃないかと。



開発者に対して入力されたデータが異常なことを伝えるためのArgumentExceptionだと思っております。だから私の場合は自分で制作したクラスでもガンガン発生させています。
大変参考となりました。ありがとうございます。こればっかりは考え方の違いですよね。どっちが悪いとかいいとかあるのでしょうか?ふぅ。
冬寂
ぬし
会議室デビュー日: 2002/09/17
投稿数: 449
投稿日時: 2005-07-01 14:40
引用:

開発者に対して入力されたデータが異常なことを伝えるためのArgumentExceptionだと思っております。だから私の場合は自分で制作したクラスでもガンガン発生させています。


例えて言うと「日本に居ながら日本国憲法に従わないようにしたい」というような事になるのでは無いでしょうか?
.NETフレームワークの中でプログラムする以上、.NETフレームワークに従わないと動作などについては保証されないのでは無いかと思います。

(.NETフレームワークの外においても平気な力量を持った方ならば、ガンガン発生させようが何しようがかまわないとは思いますが。)
もとべえ
会議室デビュー日: 2004/09/17
投稿数: 16
投稿日時: 2005-07-01 14:51
冬寂さん。レスありがとうございます。

なかなか手厳しい意見ですね。参考になります。
ArgumentExceptionは引数がエラーの時に発生する例外ですよね。MSDNにもメソッドに渡された引数のいずれかが無効な場合にスローされる例外とありますので、自分のプログラム上で引数がエラーであれば発生させてもかまわない気がしますがどうでしょう?
NAL-6295
ぬし
会議室デビュー日: 2003/01/26
投稿数: 966
お住まい・勤務地: 東京
投稿日時: 2005-07-01 14:51
引用:

もとべえさんの書き込み (2005-07-01 13:45) より:

開発者に対して入力されたデータが異常なことを伝えるためのArgumentExceptionだと思っております。だから私の場合は自分で制作したクラスでもガンガン発生させています。



これは良いと思うんですよ。
そういう引数を想定したメソッドではない。
そういう引数を渡して欲しくない。
だから事前条件として例外を発行するのはあり。
つまり、開発者向けの情報としてです。
だから、中途半端な場所でcatchして握りつぶしてはいけない。
そのメソッドを使うコードは、その例外が発生しないようにしなくてはいけない。

でも、もし、それを入力値の検証にも利用してしまうと、コードのバグで発生している例外なのか、入力値がエラーだったから発生している例外なのか判断できなくなると思うのです。
だから、入力値の検証を例外に頼るのは良くなくて、検証用のメソッドを用いて処理した方が良いと思っています。
それでも、もし、入力値の検証結果に例外を用いるなら、ApplicationExceptionを継承したカスタムな例外を作成して区別するべきです。
_________________
「伝える」とは「人に云う」と書く。
http://d.hatena.ne.jp/NAL-6295/
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-07-01 19:32
なんか、すごい伸びてる。。。私は、基本的に夜の1時間ほどしか書き込む時間がないんだよう(×_×;)


引用:

なぜパラメータ名は簡単に取得できるのに・・・。メッセージもプロパティにしてくれなかったのでしょうね・・・。


 『すべての ArgumentException は、この例外の原因である引数の名前を保持する必要があります。』と、書いてあるとおりです。“何が”悪いのか、確実に伝える必要があります。その為、ExceptionのMessageはオーバーライドされ、ParamNameと連結して表示されます。
 何に書いてあったのか忘れたのですが、エラーメッセージをデザインするときに、注意しなければいけないことがあります。

  • 誰に対するメッセージなのか
    エンドユーザと開発者で、理解できることが違います。どちらに宛てたメッセージなのかを考え、デザインします。
  • エラーの原因がわかること
    単に「エラーになりました」ではなく、なぜそのエラーが発生したのかがわかるようにします。原因がわかることで、エラーを見た人が落ち着ける、というのが1点。少しでもその気がある人なら、原因から対処方法を思いつくというのが1点。
  • 何をすればよいか、わかること
    エンドユーザに対しては特に、次に何をすればいいのかがわかるようにします。もう一度実行すればいいのか、何かの値を直せばいいのか、それともいったん終了しなければいけないのか、伝えます。何をしたらいいのかわからない、というのが、一番不安にさせます。

以上の点を注意して、デザインします。ここに開発者のエゴを持ち込むことは厳禁です。ユーザ(他の開発者を含む)は、エラーが発生したことで不安を感じます。メッセージが不十分であれば、その不安を増加させます。不安が一定以上増加すると、“クレーム”として、大きな問題になります。

 ここで、『誰に対するメッセージなのか』を考えてください。引数が何らかの異常を起こしている、というのは、開発者へのメッセージです。開発者に対しては、開発者が原因を調べてエンドユーザに報告できるように、どのパラメータに間違いがあるのかをはっきりと伝えなければなりません。パラメータ名がメッセージと必ず連結されることで、伝わる可能性が大きくなります。
# きくちゃんさんに書かれちゃった
 一方、エンドユーザに対しては、その引数がユーザ入力の何であるかを調べ、その入力がなぜいけないのか、どう修正すればいいのかを伝えなければなりません。開発者向けのMessageの内容をそのまま伝えるのではなく、言い直す必要があります。

 つまり、エンドユーザへの通知のために例外を使ってはいけません。「例外のデザインガイド」には、『通常のエラー、予期されるエラー、または正常な制御フローに対して例外を使用しないでください。』とあります。今回ケースで、出力しようとしているメッセージは、エンドユーザが行う業務の中で、「予期されるエラー」または「通常のエラー」に分類されるものです。
# FileNotFoundException なんて出てきていますが、
# あくまで ArgumentException の話。


引用:

ただ、名前や住所などの情報を格納して何かをしようとするオブジェクトがあったときに、名前や住所の各メソッドやプロパティを呼び出すのに1つ1つtry-catchでくくって「名前が不正です。」「住所が不正です。」とするのがプログラムが長ったらしくなっていやだったので、短くしたい、まとめたいということも背景にありました。


 南部さんのこの投稿(投稿日時: 2005-05-15 03:13)と、その次の私の投稿は、理解できましたか?

 まず、「名前が不正です。」というメッセージを、誰に対して発するか、考えます。これが開発者に対してなら、それでもいいでしょう。開発者がエンドユーザに「どういう入力をしましたか?」と聞いて、なぜ不正なのか、伝えればいいのです。あるいは、プログラムを見て、どういう場合に不正なのか、判断することができます。
 もし、エンドユーザに対してなら、不親切です。「なぜいけないのか」が書かれていないため、「どう直せばいいのか」がわかりません。例えば、Windowsでファイル名に「/」を含んだものを作ろうとしたとき、「ファイル名が不正です。」とだけ出てきますか?どういう文字を指定してはいけないのかが出てくるはずです。

 (おそらく)「例外のデザインガイド」に沿ったコーディングの一例を示します。
 業務フロー(の一部)を別のメソッドに追いやることで、ユーザの操作によるトリガーと、業務フロー(の一部)で本当に実現したい部分を分けます。これにより、「業務内のエラー」と、「業務外のエラー」を分けます。
 名前を入力するテキストボックスには、Validatingイベントをハンドルするようにして、エラーを引き起こす入力をあらかじめ検証するようにします。
 ところが、CLRのバグで、コーディングのしかたによっては検証イベントが発生しない場合があります。その為、業務フロー開始メソッドでは、「名前、住所が入力されていない」場合に発生する例外を「業務内のエラー」として、切り替える処理をしています。
コード:
// これを『名前や住所などの情報を格納して何かをしようとする』
// 処理のトリガーとする
private void button1_Click(object sender, System.EventArgs e)
{
	try {
		業務フロー開始();

	} catch (Exception ex) {
		// ここで受けるのは、業務フローから外れている
		// =エンドユーザでは回復できないエラー
		MessageBox.Show(
			"致命的なエラーが発生し、処理を継続できません。\n"
			+ "このメッセージが最初に表示された場合は、もう一度実行し直してください。\n"
			+ "このメッセージが何度も表示される場合は、"
			+ "次のメッセージを開発者に伝えてください。\n"
			 + "[" + ex.GetType().ToString() + "]" + ex.Message
			, "処理の継続ができません");
	}
}

// 実際の処理はここで行う
public void 業務フロー開始() 
{
	会員クラス 会員 = new 会員クラス();
	try {
		// このように、まとめて括ればよい。
		会員.名前 = this.会員名textBox.Text;
		会員.住所 = this.住所textBox.Text;

	} catch (ArgumentException aex) {
		// 未設定の例外を受ける
		// Validatingイベントで検査しているが、抜けることもあるので。
		// これが「業務エラー」に切り替える処理。
		// ただし、Messageプロパティをそのまま見せるのではない。
		// エンドユーザが、何が悪くて、どうすればよいか、わかるようにする。
		// ParamNameが画面上のラベルと対応しているのが前提としている。
		MessageBox.Show(
			aex.ParamName + "が入力されていません。入力してください。"
			, "未設定");
		return;
	}
	this.会員名簿.Add(会員);
}

// 入力されているかどうかなど、
// 入力の正当性は前もって検査する。
// ここで検査することで、会員クラスのプロパティ設定で例外を送出させない。
private void 会員名textBox_Validating(object sender, System.CancelEventArgs e) {
	if (会員名.textBox.Text.Length == 0) {
		// ErrorProviderと連携させて、何がダメで、
		// どうすればいいのかをエンドユーザに伝える。
		e.Cancel = true;
	}
}
__________
public class 会員クラス {
	private string _名前;
	private string _住所;

	public string 名前 {
		get { return this._名前; }
		set {
			// 設定する例外メッセージは、開発者が対応できるものなら良い。
			if (value == null) throw new ArgumentNullException("名前");
			if (value.Length == 0) throw new ArgumentException("長さが0", "名前");
			this._名前 = value;
		}
	}
	:
}



_________________
もとべえ
会議室デビュー日: 2004/09/17
投稿数: 16
投稿日時: 2005-07-01 20:16
引用:

NAL-6295さんの書き込み (2005-07-01 14:51) より:
でも、もし、それを入力値の検証にも利用してしまうと、コードのバグで発生している例外なのか、入力値がエラーだったから発生している例外なのか判断できなくなると思うのです。
だから、入力値の検証を例外に頼るのは良くなくて、検証用のメソッドを用いて処理した方が良いと思っています。
それでも、もし、入力値の検証結果に例外を用いるなら、ApplicationExceptionを継承したカスタムな例外を作成して区別するべきです。



Jittaさんが書かれた(会員名textBox_Validatingメソッド)で会員オブジェクトに代入して例外を発生させて対応すれば、検証も可能ではと思いました。(勘違いしている可能性大ですが・・・)また、名前などの項目が未入力でもいいようになったことを考えればそちらの方がスマートな気がしますが・・・。

ただ、MSDNで書かれているのであれば、納得するしかないですね。「例外はプログラマへのメッセージ」、「なるべく例外を発生させないようなロジックを組むこと」という基本をしっかりと抑えておこうと思います。

なぜ、例外をなるべくおこさないようにしなければいけないのか?ということをいろいろ調べると以下のサイトに行き着きました。

例外処理の実施

ここだと例外を処理する時間がかかるためです。と記載されているため、パフォーマンスのためという理由が大きいのでしょうか?また、どこからどこまでを予期しないエラーとするかも難しいですね。それだったら、例外について対応した方が、間違いないような気も・・・。(もちろんエラーコメントはラッピングします。)ムムム・・・。

[ メッセージ編集済み 編集者: もとべえ 編集日時 2005-07-01 20:54 ]

[ メッセージ編集済み 編集者: もとべえ 編集日時 2005-07-01 20:56 ]
餅宮餅吉
ベテラン
会議室デビュー日: 2005/03/04
投稿数: 57
お住まい・勤務地: 月餅のうまい店の隣
投稿日時: 2005-07-04 13:40
#まとはずれかもしれませんが・・・

 今回のもとべえさんの場合、値を受け取るクラスの実装は今のままでいいと思います(チェックし例外を発生させる)が、クラスの役割が明確にないような気がします。
 そのクラス(メソッド)は値を受け取るのですから、そのクラス(メソッド)の役割として受け取った値を、チェックするのは当然だと思いますが(例外をスローするかはどうかは置いといて)。
 
 しかし、その値を受け取るクラス(メソッド)でチェックを行うのは誰のためでしょうか?システム利用者のためでしょうか?開発者のためでしょうか?その点が問題だと思います。

 そのクラス(メソッド)は誰の為に何を行うのかを考えればエラーメッセージの内容、処理方法もそれぞれに応じたものになるのではないでしょうか?
 
 もとべえさんの場合は、一人で開発していらっしゃるご様子なので、意識しにくいのかも知れませんが、値を受け取るクラスと、画面クラスで実装者が異なる場合を考えて見れば分りやすいのではないでしょうか?

 開発者の意識
 画面側>>入力ユーザ、開発者を意識している。
 値を受け取る側>>入力する側(画面,XML,テキスト.DB等)が何であるか意識できないので、
         クラスを使用する開発者を意識している。
 
 エラーメッセージ
 画面側>>ユーザに分るエラーメッセージ(例:「XXXXXXの値は必須項目です、入力してください。」)、デバッグ用の開発者向けのエラーメッセージ
 値を受け取る側>>開発者向けのエラーメッセージ。(例:「XXXX値が入っていません。」)

 メッセージ内容が開発者向けとユーザ向けが同じようなものになる場合でも、同じ様に思えるだけで、同じにはならないと思います。

[ メッセージ編集済み 編集者: 餅宮餅喜 編集日時 2005-07-04 13:43 ]

スキルアップ/キャリアアップ(JOB@IT)