- PR -

C# 引数やローカル変数の名前を取得する方法は?

投稿者投稿内容
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-03-01 07:37
引用:

ひろしさんの書き込み (2008-02-28 21:34) より:

// リファクタリングでparam1の名前を変更すると
// 文字列"param1"が古いままでバグになってしまう

public void f(int param1,int param2)
{
if (param1 < 0 || param1 > 100)
{
string paramName = "param1";
string message = "パラメータが不正です";
throw new System.ArgumentOutOfRangeException("param1",param1,message);
}
.....
int index = 0;
.....

}


 「文字列"param1"が古いまま」というバグを作り込まないためには、ここは「第1引数」とすればいいでしょう。引数の数が変わるとかいわれると、また考えないといけませんけど。

 理由は、「パラメータが不正です。(param1)」という例外が表示されても、エンド ユーザには理解不可能だからです。
 例外は、開発者に対して表示するものです。なので、開発者が理解できればそれで十分です。開発者に理解してもらうためには、ここは「第1引数が想定の範囲外です」と表示されれば十分に伝わるでしょう。

 つまり、エンドユーザにこのメッセージを見せてはいけません。ここは f が何を行うかわかりませんが、「〜の処理をしているときに、設定された値が計算可能な範囲を外れました。**の値を調整してください。」というようなメッセージが表示されるべきでしょう。このとき、**は param1 ではなく、画面上の入力値を示す言葉であるべきです。

 あるいは。「実行時の入力値チェックに例外を使うな。」
 「例外 ガイドライン」あたりで検索すると、どんなメッセージにしろとか、どう使えとか、出てきます。


> ビルドされた後にはローカル変数に名前はありませんから、取得する方法もありません。
 この説明だと、「デバッガで、ローカル変数名入れたら値が見られるじゃねぇか。名前がないなら、どうやって対応取ってんだよ」といわれると思う。
いや、開発者なら、この説明でわかってもらいたいけど。そういう意味では、アセンブラやっていて欲しいよね。変数名がない世界。。。
ykSiR
会議室デビュー日: 2006/10/03
投稿数: 16
投稿日時: 2008-03-01 10:56
引用:

Jittaさんの書き込み (2008-03-01 07:37) より:
 例外は、開発者に対して表示するものです。なので、開発者が理解できればそれで十分です。開発者に理解してもらうためには、ここは「第1引数が想定の範囲外です」と表示されれば十分に伝わるでしょう。


メソッドの呼び出し時に第○引数ではなく引数名で指定する場合などを考えると十分とは言いきれないと思います。
例としてASP.NETでObjectDataSourceのParameterを指定する時など。

とは言ってもソースをちょっと見れば済む話ではありますが。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-03-02 00:25
引用:

ykSiRさんの書き込み (2008-03-01 10:56) より:
引用:

Jittaさんの書き込み (2008-03-01 07:37) より:
 例外は、開発者に対して表示するものです。なので、開発者が理解できればそれで十分です。開発者に理解してもらうためには、ここは「第1引数が想定の範囲外です」と表示されれば十分に伝わるでしょう。


メソッドの呼び出し時に第○引数ではなく引数名で指定する場合などを考えると十分とは言いきれないと思います。
例としてASP.NETでObjectDataSourceのParameterを指定する時など。

とは言ってもソースをちょっと見れば済む話ではありますが。


だったら余計に、変わるかもしれない名前ではメッセージを出さないようにすればいいと思います。
あるいは、"param1"という、「太郎さん、次郎さん」みたいな名前ではなく、固有の何かを示す名前を最初に与えるべきです。または、例外メッセージには固有の名称を使うべきです。

 基本は、開発者に見せるためのメッセージです。エンドユーザに見せてはいけません。


 というか、このコードでは、検査例外として、Exception を使おうとしているように思います。まずは、その認識を捨てるべきでしょう。.NET では、検査に例外は使わない、というのがガイドラインです。検査メソッドを用意して、例外は想定の範囲外の時のみスローされるように設計しましょう。
ykSiR
会議室デビュー日: 2006/10/03
投稿数: 16
投稿日時: 2008-03-02 09:39
引用:

Jittaさんの書き込み (2008-03-02 00:25) より:
だったら余計に、変わるかもしれない名前ではメッセージを出さないようにすればいいと思います。
あるいは、"param1"という、「太郎さん、次郎さん」みたいな名前ではなく、固有の何かを示す名前を最初に与えるべきです。または、例外メッセージには固有の名称を使うべきです。


基本的にJittaさんのおっしゃってる内容については納得させられるものばかりなのですが、ここだけ気になります。

今回の"param1"はメッセージではありません。
例外の原因となったパラメータの名前です。
http://msdn2.microsoft.com/ja-jp/library/dsyf5bb2(VS.80).aspx

ガイドラインに従った上でArgumentOutOfRangeExceptionをthrowするコードを書くことがあるのかについては疑問なので、気にするようなポイントではないかもしれませんが。
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2008-03-02 20:37
ご回答ありがとうございます。
Jittaさんのご指摘は勉強になります。
自分の理解度を確認するために質問します。

> というか、このコードでは、検査例外として、Exception を使おうとしている
> ように思います。まずは、その認識を捨てるべきでしょう。.NET では、検査に
> 例外は使わない、というのがガイドラインです。検査メソッドを用意して、例外
> は想定の範囲外の時のみスローされるように設計しましょう。

「検査メソッドを用意して...」という言葉の意味は、
「検査ロジックをメソッドに含めるのではなくて、検査メソッドとしてメソッド
から分離した上で、メソッドを呼び出す前に、呼び出し側で検査メソッドによる
検査を済ませ、メソッドには常時検査済みの引数が与えられるようにしなさい。」
という理解で正しいでしょうか?

例外を使わないとして、検査メソッドが引数の不整合を検知した場合、呼び出し側に
どのような方法で通知するのが妥当でしょうか。返り値の数が増えますが、
(例えばPurseに対するTryPurseのように)フラグを1個追加するのが妥当でしょうか?
ugaya
会議室デビュー日: 2006/08/03
投稿数: 18
投稿日時: 2008-03-03 08:05
入力値の検査はUI側にまかせ、ビジネスロジック側では引数を信頼する形でよいのではないでしょうか?

皆様のご指摘のように、一般的な業務アプリケーションの場合に検査例外の様に例外を投げることは.netでは推奨されていません。

ただもしかしたらメソッドの利用時にそのメソッドのソースコードが隠蔽されている場合がある(たとえばフレームワークの様なものを開発している)場合は検査例外の様に例外を投げなくてはならない場合もあるかもしれません。

ビジネスロジックを不特定多数の他の開発者が利用するWebサービスとして公開するような場合では、ひろし様のおっしゃるように引数の数(あるいは戻り値のかたち)をコントロールして業務例外を通知します。

個人的には例外を投げなくてはならない場合というのは、基本的にソースコードにアクセス不可能な人間に提供するAPIの場合にしかないと思っています。

(最近.net framework自体のソースコードにアクセスできるようになった事を考慮すると正直微妙な気もしますがww)
indigo-x
大ベテラン
会議室デビュー日: 2008/02/21
投稿数: 207
お住まい・勤務地: 太陽の塔近く
投稿日時: 2008-03-03 08:38
(最初にずれた答えですいませでした)

私は時間と層の違いで分類した方がよのではと思います。

時間的
1)開発時は開発者の為--------------->Assert,throwなど
2)運用時はエンドユーザーの為------->分かりやすいメッセージ

層的
1)UI層は--------------->例外はいけません
2)BL層は--------------->例外もあり
3)framework層は-------->例外が基本(もちろんリターン値もあり)

のマトリックスで考えた方がよいのでは。
例)入力値の検査は開発時はthrowしても良いですが、運用時はNGです。


ただ、引数の与え方がよほど難しい場合以外、引数のチェックなど
必要がないような気がしますが。(使用する人は知っていはず)
(仕様書とかXMLコメントをちゃんと書けば問題なし、※コード解析時に警告でますが)
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2008-03-03 11:23
 皆さんのアドバイスに感謝しています。
これまで「どんな引数がきても対処できるよう、受け手側(メソッド)が責任を持って徹底的に検査しなければならない。」という思い込みに囚われていました。アドバイスのお陰でようやく解放されました。文献を読んだだけでは腑に落ちず、掲示板のアドバイスと文献を見比べることで腑に落ちることが時々あります。ありがとうございます。

今、ソースコードの品質を向上させるため色々試行錯誤をしています。
引数の検査をどうデザインするかの検討もその一環です。
私が例外について参照した文献を参考までに掲載しておきます。

参考文献
「プログラミング.NET Framework」より第5部第18章「例外処理」
「コードコンプリート(上)」より8.4章「例外」
(日経BPソフトプレス)

例外のデザインのガイドライン(MSDN)
http://msdn2.microsoft.com/ja-jp/library/ms229014(VS.80).aspx

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