うらおブログ(移転しました)スマートフォン用の表示で見るやねうらおブログ(移転しました)この広告は、90日以上更新していないブログに表示しています。2010-09-29C#のvarとtry〜catchが糞すぎるC#C#3.0からはvarと書くと型を明示的に指定しなくても済む。HogeClass();しかし例外処理をするためにこれをtry〜catchで囲みたいとする。(hoge!=null)hoge.YYY();}このプログラムはコンパイルが通らない。catchのなかでは変数hogeにアクセスできない。try節が終わっているため、hogeのスコープが終わってしまうのだ。仕方ないのでhogeを外部のブロックに出す。(hoge!=null)hoge.YYY();}しかしこれまたコンパイルが通らない。hogeの部分、型推論してくれない。sugarだと思ったほうがいいのかも知れない。そこで行頭を次のように書き直す。(hoge!=null)hoge.YYY();}これまた正しくない。HogeClassのところで例外が発生した場合、hogeには何も代入されることなくcatch節に飛ぶ。このときhogeは未初期化のままで、未初期化の変数にアクセスしていることになる。よって、行頭は次のように書くべきだ。(hoge!=null)hoge.YYY();}とりあえず書けた。このように変数宣言時にnullを代入したあと、try〜catchがやってくるのは、もはや常套句である。try〜catch」パターンと呼んでいる。略してTryoutパターンである。以下でもそう呼ぶことにする。このパターンをたまに初心者の人が間違えて次のように書いてしまう。HogeClass()で例外が起きるとcatchされない。何のためにtry〜catchで囲っているのかわからない。Tryoutパターンはhogeがcatchを抜けたあともスコープが生きていて気持ち悪い。仕方ないのでブロックに入れる。(hoge!=null)hoge.YYY();}}とてもダサくなってきた。最初にHogeClassと明示的に書かなくてはならない。Yourself)原則に反するだけではなく、もっと長い名前の複雑なクラスになった場合、とても大変だ。「インテリセンスが自動的に補完してくれるじゃないか」と言われるかも知れないが、そうとは限らない。(hoge!=null)hoge.YYY();}あるメソッドの返し値をvarで受け取る場合だ。この型がとても複雑でとても長いとしよう。>みたいな呪文のような型名だ。こんなものは手で書きたくない。2010の標準機能にもそのような機能は備わっていない。scope」を選んで外のブロックに移動させ、そして手で「=null」と追記している。この一連の動作をいままで何百回やったかわからない。その手順自体が一発で出来て欲しい。Resharperのpluginを書けば出来るのだが、こんなもののためにpluginを書きたくないし、Resharperのpluginの仕様はバージョンアップごとに変わるので関わるのは結構嫌だ。snippetなどでどうにかならないのか?あるいはtry節やcatch節が変数スコープを制限するという言語仕様自体がおかしいんじゃないか?varがきちんと型推論してくれないのがおかしいんじゃないか?などと考えてしまう。どれも真実なのかも知れない。"だとか)があって、次のように書けて欲しい気はする。nullが代入されていることが保証されないといけないが。"}"で揃わないのはあまりエレガントでもないような...。私はC#ではあと数万回ぐらいはこのTryoutパターンのお世話になる気がするんだけど...みんなはこのコードに嫌気が差したりしてないのかな...。以下のコメントをいただきました。返信が長文になる&とても重要な問題なのでここに追記します。行をtryの外側に出す書き方でも問題ないはずだと思っています。出来の悪いクラスを使う場合は、Tryoutパターンで書かないとだめですが、その場合は諦めます。「constructorは、例外を投げるべきではない」<出典を忘れてしまいましたが、一般的なルールですよね?「constructorは、例外を投げるべきではない」というのは、C++ではそういう設計でプログラムすることが多いです。これは、C++ではGCが無いため、コンストラクタで例外が発生したとき(このときデストラクタが呼び出されない)にリソースのリークを防ぐのが難しいからです。次のようなコードです。Resource2のところで例外が発生すると、このままデストラクタは呼び出されないのでResource1がリソースリークします。これを防ぐには、スコープアウトするときにリソースを解放してくれるような(=オブジェクトをdeleteしてくれるような)ポインタを用います。boost::shared_ptrです。コンストラクタでの例外が発生した場合のためだけにm_my_resource1をboost::shared_ptrにするのはとても大掛かりです。ゆえに、C++ではこんな設計には普通しないというだけです。collection)がある言語では、このような問題は無いのでコンストラクタで例外を投げるような設計が(必ずしも)悪い設計だということはありません。Frameworkにはコンストラクタで例外を投げるものがたくさんあります。使うものとしてStreamReaderが挙げられます。StreamReaderのコンストラクタでは引数で指定されたファイル名のファイルが存在しなければ例外を投げます。確かにコンストラクタで例外を投げないというルールを作ればTryoutパターンは簡潔に書けますが、コンストラクタでファイルをオープン出来ないので記述が冗長になります。次のように書くことになります。StreamReader();sw.Open("test.txt");例外はその場で必ず捕捉するわけではないのに対して(つまりTryoutパターンが必ずStreamReaderを使うごとに必要になるわけではないのに対して)、↑の表記はStreamReaderを使うごとに毎回必要になります。よって、ソース全体では、このような冗長な表記になるデメリットのほうがTryoutパターンが簡潔に書けないデメリットを大きく上回ります。ゆえに、コンストラクタで例外を投げるデザインのほうが優れていると私は思います。1;の1行目で例外が発生した場合にpiyoにアクセスしていいのかという問題が出るんですよね。null」という仕様にするなら何とかなるか。「スコープを広げると」というのは、「try〜catchでの変数スコープを広げると」の意味ですね。sugarで、次のようにプリプロセスで変換されると私は考えます。{}↓以下のように変換される。{}ゆえに、piyoに関しては、hogeのあとに宣言して、catchのなかでpiyoにアクセスしていたのでは未初期化のままアクセスしていることになりますから、これはコンパイル時に警告が出ます/出せます。この点では問題ないかと思います。10:31型推論を使いたいときはtryをネストさせていました。//共通の例外処理}節子、それベストアンサーや!!tryを二重にするのは私もそうやって書くことはあります。それはそれで使えるパターンだと思います。varをexplicitに書かなくて済む、一番いい解決策だと思います。冗長になりますが、どうしてもvarを使いたいときはその方法しかないですもんね。なんでここでtextにアクセス出来ないの?馬鹿なの?死ぬの?こういうケースも同様で、varを外部のスコープに移動させると型推論させられないので結局、C#のvarの型推論が甘すぎるという結論にはなると思います。参考)C#の型推論は怠けすぎhttp://d.hatena.ne.jp/akiramei/20100929/1285759272そんなわけで、この問題はC#の開発チームのほうにfeedbackすべきだと思いました。あとでやっておきます。Web2をデザインツールとし...2008-11-25それmicrothreadで書くべきだよC#でWebBrowserクラスというWebブラウザのclassがある。電子書籍になるに至るまでの話ブログちょっとだけ移転のお知らせ時代はまだゲームセンターあらしに追いつかないのかやねうら王、電王戦バージョン提出しました将棋の神様のレーティングはいくつなのか?月別アーカイブはてなブログをはじめよう!yaneuraoさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。