著作一覧 |
正月はマンガを読みまくることになぜかなったのだが、思い出したのは、以下略の中のエピソードで、監禁したヤクザの子分を「アニメ マンガ抜きでは生きられない体」にオトすやつ。いろいろなマンガを与えて無理矢理読ませるのだが、、途中まで与えてネタばらししたりとか精神的に追い詰めていくのだが、一番強力なのはベルセルクのやつ。
「コレ読めやベルセルク」
「何巻までわたしたの?」
「1~12巻までと」「14巻~最新刊」
「悪魔かおまえは」
これはおっかないなぁ。
年末に品川のジャスコに行ったら、子供がマンガを中人買いしていて、それがxxxholicの1~5巻だった。
で、おれは同じ作家というか集団(ジガヴェルトフみたいだな)のツバサはそれほどおもしろいと思わなかったので(子供向け説教がくさいし、字が細かすぎて読めないし(※)、絵柄も好きじゃないし、長いし、その他いろいろ)無視していたのだが、なんとなく渡されたのでつい読み始めたのが元旦のことだった。
が、やばい。これも説教くさいが、それほど気にならないぞ。
というわけで、2日に品川のジャスコに行って、本屋に残っていたのを全部買わせてきた(お年玉やったし)。
それが6~10巻。そこまでしか本屋に無かったからだ。
で、今日(これ書いているのは3日)は別の本屋へ行くことになるわけだった。
DVD付き ×××HOLiC19巻 限定版 (講談社キャラクターズA)(CLAMP)
(これは買ってやるかなぁ)
※)以前、竹熊日記を読んでいたら、売れる本として少年向け単行本サイズではなく、一回り大きいやつ、と書いてあって、なぜだ? と思ったけど、もしかしたら、おれ(週刊少年誌第2世代くらい)±10歳くらいで、老眼になると少年向け単行本は読めなくなるってのもあるかも(かつ、マンガくらい余裕で買える世代でもある)。というか、既にバスタード欄外とか絶対に読めないし、まして文庫版の三原順が読めないのなんのって(もっとも、眼鏡やコンタクトさえ外せば読めるのは近視のありがたさだ)
で、妹にCLAMP持ってたら貸してくれと言ったら、レイアースというのが6冊出て来たので、子供と読んだ。
魔法騎士レイアース 新装版 (1) (KCデラックス)(CLAMP)
(まったく、知らなかったがーー子供も名前は聞いたことあるという程度らしいーー読みつがれている本なのか)
絵はばかみたいに眼がどでかい少女漫画だし(最初、読む気をなくしていたのだが、子供が慣れれば気にならなくなると言ったので読んでみた。確かに気にならなくなるな。でも、それがマンガとして良いことなのかは疑問だけど)、驚くほど紋切り型で、そのくせここぞというときに延々10ページ以上も無駄なお笑い劇場になるし、モコナという謎の異化効果がぷにょぷにょするし、しかも猛スピードで話は進み、あっという間にラスボスが出て来て倒してめでたしとなるかと思うとドカンと話の前提を引っくり返すので、驚いた。すごい作家だ。
もっともこれも説教くさいがそれほどはなにつくわけではない。多分、疾走感があるので、べたつかないのだろう。説教の内容については、そう言えば集団なんだなぁと気付くが関係あるかどうかはわからんけど。
一方、xxxholicは、17抜きで18まであるという状態になった。で、18は読まれないまま17の入手待ちとなる。
友人と、なぜかブルックナーの話になる。
おれは、中学生の時、最初に買ったクラシックのLPがケンペがミュンヘンを振ったブルックナーの5番だということもあって、結構ブルックナーにはうるさかった。が、その後、あまり聴かなくなった。なので、最近の傾向にはうとい。
(文字通り擦り切れるまで聴いたので、1楽章の出だしはシャーシャーボシャーボンボンシャーボシャーみたいな感じになってしまった。シャーシャーとか書いても今のわけぇもんにはわからんだろうてなぁ。しかし、良いジャケットだというか、当時、朝日新聞の夕刊の1/4面くらい使ってテイチクが広告を出したのを見て買う気になったのだが、まるで夢のようだな。テイチクってのも、新聞にそれだけのスペースで広告を出していたってのも)
多分、つきものが落ちたのは、朝比奈隆が日本じゃなくて東京に来て新日本フィルで8番を振るのを聴いたのが原因だと思う。
最後、まるでビルが崩れ落ちるようにソーミレドと来て、周りがパチパチの大嵐になったわけだが、なんか冷めてしまったのだった。
で、友人が言うには、ブルックナーの3番のワーグナーだがあれは前衛だよなぁ、と。
待てよ? とおれが疑義をはさむ。どうってことない作品だろ、あれは。どちらかというと、6番のほうが変だと思うし、むしろ3とか4とかは長さも普通だし、そんなに前衛とは思えないな。お前はハンスリックか?
いや違う、と友人が言う。そもそもブルックナーがまともに認められたのは7番からじゃん。
え、そうなの? 5番とか長いけど普通だと思うけどなぁ。まあ、6番は変だが。
いや、普通に交響曲を書けるようになったのは7番からで、おかげで交響曲作家として認められたんだよ。これ史実な。
そうなのか? あまり納得いかないけどな。
というのは、と友人が言う。7番が認められてブルックナーは、悟った。
何を?
おれは間違っていた、と。と友人が言う。
えー。
で、やつは、3番を書き直す。完全に。
えー。
で、やつは、4番を書き直す。完全に。
えー。
5も書き直す。
そうなのか?
6は書き直している最中に力尽きてくたばったので、まだ妙なところが残っている。その間に8も書いたし、9も途中まで書いた。結局、書き直しをしなければ、ショスタコヴィッチみたいに15曲は書いていたと言われている。
嘘くせぇな。
いや、これ事実。
ふむそうなのか?
で、こないだあたりから、原典主義者が3や4の原典を見つけてきた。つまり、書き直す前のやつってことだ。
なるほど。
で、それが日本でやったのをおれは聴きに行ったのだよ。
ふむそれで?
で、会場全体がびっくりしていた。
なぜ?
ハンスリックが正しいことがわかったからだ。
えー。
つまり、ハンスリックが怒りまくったブルックナーの3番とか4番ってのは、こういう音楽だ。最初さわさわと始まり、突然でっかな音が鳴ってずーっとでっかい音が鳴ってずーっと盛り上がりもへったくれもなくでっかな音が続く。はいブルックナーパウゼ。でっかな音でっかな音でっかな音。はいブルックナーパウゼ。
なんじゃそりゃ? っていうか、オルガン奏者の音楽そのものってことか?
その通り。あれは驚くぜ。突然でっかな音が鳴るとそのままでっかな音が鳴りまくってずーっとそれが維持されて突然ブルックナーパウゼ。提示部がどれで展開部がどれでとか全然わからん。というか主題はどれ? おれは今どこにいるんだ、というかアナリーゼを拒否するほどの大音量。うるせぇなー、はいブルックナーパウゼ。というわけで、今、聴けるワーグナーとかロマンティックとかは、7番で交響曲作法を理解した男の手によるまともな交響曲。
まあ、オルガン奏者ってのはトッカータは理解していてもソナタ形式を理解しているとは思えないしなぁ。
まさに、そういう調子で6番までは書いてたってことだ。
信じがたいなぁ。
いや、本当だよ。ひどい代物だぜ。少なくとも原典版は二度と聴かないだろうな。(と言いながら友人は去って行く)
というわけで、信じがたいので探したらふつうに原典版を売ってるじゃん。指揮者はハイヒールで颯爽とした指揮をするヤング(ホーレンダー引退記念良かったし、CDで聴いたヴァルキューレも良かったな)なので買って聴いてみた。
ブルックナー:交響曲第3番「ワーグナー」(1873年初稿版)(ヤング(シモーネ))
うーん、まともだけどな……と思うのだが、友人の話が頭にあるからか、突然でっかな音というのは言われてみればそうだなぁ(というか、5番とかもそうだし、それがブルックナーだと思うけど)。さすがに、第1楽章の最後(コーダかな?)はひどい話な気はするが。というわけで、初稿でもなんでもなく、友人はもともとブルックナーを聴いたことがなかったのではないかという疑問が湧かなくもない。
ああ、でも3楽章の最後はさすがにうるさ過ぎるかも。聴衆がマーラーと取り巻き10人ほど残して全員帰ってしまったというのもむべなるかな。
というか、おれはやっぱり歌もののほうが好きだなぁ。
ウィーン国立歌劇場ホーレンダー総監督フェアウェル・ガラ(2DVD)(DAMRAU DIANA (soprano))
(赤鬼が歌うホーレンダーちゃんの歌がなぜか耳に残る)
いや、というよりも、このホーレンダー総裁引退記念ガラが2600円で楽しめるというのは夢のような話だ。出産直後で太りに太ったネトレプコがわたしが街を行けばを唄い(良く出演を承諾したよな)、フリトリがモーツァルトを唄い、デッセーも出てくるし、名前忘れたけどとんでもない巨漢の白鳥の騎士、(コルンゴルトが入っているものポイント高い)。でも一番好きなのはローゲだけど。
で、ソーミレドのばかばかしさをおれは次のように聴いたのだった。
地方のオルガン奏者が大都会のいかした作曲家にあこがれて上京してきて、交響曲を書くっていうのは、つまるところ、ポリスなんじゃないか? ということだ。
アンディ・サマーズは売れないジャズギタリスト、スティングはしがない高校教師、コープランドは忘れたが、中途半端に年食った連中が一花咲かそうと髪をツンツンにして1曲2分の3コードロックをやる、ちょっぴりレゲエも取り入れてという構図にそっくりだ。あるいは、ソフトロックが好きなドアーズ狂いのインテリ大学生がマーケティングでベースブンブンのストラングラーズになるとか。
生まれついてのパンクなジョンライドンがヴァグナーで、梅毒で精神病院へ入れられたシューマンがシドヴィシャスなら、あるいはカリブの熱い風ボブマーリーがポーランドの寒い風ショパンなら、つまりこいつらは本物なわけだが、ブルックナーって、どうにもいかさまくさい。チェッカーズっぽいかも(後年、本物になるとか)。
どでかい音がボーボー鳴りまくるのを聴くのは快感だから(それはロックの音量と同じことだ)、いかれた若者がかぶれる(その中にマーラーとかシャルク兄弟とかがいる)のは当然だし、教養人が眉をひそめる(ハンスリック)のも当然だ。
おれは本物が好きだから、ヴァーグナーとリスト(上の喩で行くと、この男こそ孤高のザッパか、常に前向きニールヤングに相当する)にはお金を使うが、ブルックナーを聴くのはやめたのだというか、だったらポリスを聴く。
(1970年代のブルックナー)
で、7番に相当するのがシンクロニシティなんだろうな。
(7番で一皮剥けたブルックナー)
荒井さんからいただいた実践F#を読み始めた。今、大体1/3強というところ。
実践 F# 関数型プログラミング入門(荒井 省三: いげ太)
大体、5章までだが、ここまでは1項あたり1文法という形式で、簡単な説明、対話型シェルの出力、付随説明が繰り返される。読みやすい。どうも11章がおもしろそうなのだが、順番に読んでいるのでもう少し先のことかな。
・どうでも良いタイポ
P.139 リスト5-47のタイトル 「ガート」→「ガード」
(後1つ見つけたけど、わからなくなってしまった)
・引っ掛かったところ
P.106 関数合成演算子の向きで、areaOfCircle << roundという例と、areaOfCircle >> roundという例が出ているのだが、これは例があまり良いとは思えない。前者はroundを先に適用、後者はareaOfCircleを先に適用しているのだから、結果が異なるような数値を例にすれば良いのだが、そうなっていないのがちょっと減点かなぁ。
<- が突然P.172のリストで出てくるように思うのだが、ラムダ式のパラメータとボディの区切りの->とも、パターンマッチのパターンと結果式の区切りの->とは違うので説明が欲しいところ(前に出ていたのかも知れないけど、->や<は独立したオペレータとかではないからか索引に出ていないのでわからない。
なんとなく、.NET Frameworkを使えば簡単にアドレスを取れると思っていたが、実際にはそんなに単純でもなかったのでメモ。
検索で比較的上位に出てくるのはDnsにホスト名を与える方法だが、イントラネットやルータ内部では役に立たない(もしかしたら役に立つ環境があるのかも知れないが(追記:どちらかというと、役に立たない環境のほうが異常だとわかったが、種々の制約からそういう環境もある)、試した限り127.0.0.1のループバックアドレスになる)。したがって、アダプタ情報を列挙していくしかない。
後、IPv6のアドレスだったりすることがあるので、IPv4のアドレスが欲しければ、そこでもフィルタリングが必要。
結局、以下のようになった(.NET Framework 2.0以降)。
using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; public class MyAddress { public static void Main() { foreach (var intf in NetworkInterface.GetAllNetworkInterfaces()) { if (intf.Supports(NetworkInterfaceComponent.IPv4)) { foreach (var addrInf in intf.GetIPProperties().UnicastAddresses) { if (addrInf.Address.AddressFamily == AddressFamily.InterNetwork) { if (IPAddress.IsLoopback(addrInf.Address)) { continue; } System.Console.WriteLine(addrInf.Address.ToString()); } } } } } }
この処理を元に、System.Console.WriteLineの箇所でList
とある事情で群馬へ行ったら、突如妻が富岡へ行かないか? と言い出した。
行ったことないので、では行こうとなり、関越自動車道から上毛(だと思うが千葉じゃないんだから覚え違いだなぁ)自動車道へ入ってやたらオービスが多いなぁと1時間弱で富岡へ着いた。
製糸場まで行くと駐車場はないので、手前の十字路を右に曲がって30メートルくらいで右にある市営駐車場へ入れる(と、製糸場の入り口にいる係のおじさんに教えて貰う)。30分まで無料、次は100円と安い。それより手前には民営のやつもあるが、そんなに高い訳でも無いので少しでも歩く量を減らしたければ民営を使えば良い。で、5分くらい歩いて製糸場へ。
レンガのきれいな工場跡や、お雇い外国人のこじゃれた宿舎とかが残っていた。世界文化遺産化運動中らしい。
で、以前、山形浩生のとこで読んだことがある、女工の日記とかの展示などを観たり。生糸に入っている蛋白質をアルカリで脱いて絹にするとかで、触って違いがわかるようにそれぞれを展示してあったがアルカリって怖いなぁと思う。で、工場の裏手に川があって、そこには下水を完備して工場を清潔に保つための機構を備えていたと書いた看板が立っているのだが、アルカリの廃液も垂れ流しだったのかなと気になったり。
製糸場と女工というとステロタイプのああ野麦峠というイドラ(原著とは無関係に生成されているもの)があるが、それから受ける印象とは異なる、新しい技術を率先して身につけ地元の産業発展の礎たらんと欲する強いモティベーションと、家が貧しいから親兄弟のために身を犠牲にして女工になるという悲惨な私意識では、同じことも違って見えるからかなぁとか、あるいは、一人前になるための丁稚奉公というキャリアパスの近代版と捉えるか、苦界へ身を沈めるってやつの工業版と捉えるかの差とか。もっとも、半官で赤字無双の富岡と岡谷では事情が異なるのかも知れないけど。
いずれにしても、ああ野麦峠自体はまっとうなルポルタージュなので、本物を読まずにイメージで云々しても歴史はわからない。
実践F#を読みながら試すのに、諸般の事情からUbuntuマシンというかネットブックを使っている。
以下のようにインストールした(またはしていない)。
-CTPのzipをダウンロードする。
-展開する。
-install-mono.shを無視する。
-binをPATHに追加する。
-alias fsi=fsi.exe
Ubuntuにいれたのは、mono-completeで、--versionすると2.4.4と出るから一つ以上前のバージョンっぽい。
そのためだと思うが、zipのルートにあるinstall-mono.shに従って、mono.snkでサインしようとすると、unknown blob formatというエラーとなる。でも、試しにfsi.exeを実行すると期待通りに動く。であれば、他のmonoグラムから使う訳では無いので別にGACに入れたりMONO_PATHを使わなくとも良いかなぁと、PATHを通すだけにしたのだった。
浅草の焼肉屋に行ったわけだが、
・ずーぅっと昔、うますぎてもうしわけないっすというコピーの店に入って、えらく客単価が高くて、確かにうまいが(過ぎるとは思わないが)、妙な店だなぁと思ったのだが、まだ営業していて、これが老舗ってやつかなぁと感慨にふけった。似たような時代感を覚えさせる店が渋谷の井の頭線ガード下にあったのだが、こっちは再開発されて廃業してしまったのと好対照だと思った。つまり、再開発されない街という印象だが。
・銀座線への道: ななめに切り欠いた看板が出ている狭い地下への入り口から降りると、たとえば香港のチョンキーマンション(漢字忘れた)みたいな不穏(だが、妙にひとなつこいというか、異様な親密性があるというか、たとえばコンクリの壁に対する横穴住居みたいな飲み屋が何軒かあって、その時、誰か忘れたけど、じゃりんこチエみたいだなぁとか言っていたが、まさにそういう感じだ)な雰囲気の地下商店街で、だいたいそういうところって、天井とかに鍾乳石の胎児のようなものがはえかけていたりするのだが、原始と現代の狭間に生じた断層みたいなもので、通りすがるには好きな感じだ。
家の玄関の扉は電子キーになっているのだが、アンロックボタンを押しても開かなくなっているので、電池切れだと思い、新しい電池を買ってきた。
しかし分解してみると、電池交換を意識していないとしか思えない作りではあった。
まず、開けるための+ネジがメガネ用でなければだめで、おれはメガネ用を持っているが、ふつうの家庭にあるような8本セットみたいなのだと開けられないだろう。しかし、電池自体には大きく型番が書いてあるから問題ないと思っていたのだ。つまり、最初に分解した時点ではそれほど交換を意識していないとは思わなかった(が、細かな部品がばらけるので、あまり家庭向けの仕様ではないなぁとは思った)。
しかし、いざ交換しようとしてみると、電池自体は透明なシールで止めてある。型番がやたらと読みやすいはずで、それは電池自体の刻印ではなく、文字自体がシールに印刷してあったのだ。かくして、そのシールをはがさないと交換できないというところで嫌な予感にざわざわする。
案の定、予感は的中する。いくらやっても鍵は動作しない。
電池切れではなかったのだ。
だが、可動部品としては、ロックとアンロックのボタンくらいしかなく、精密機器だとは思うが、たとえば何かの衝撃が原因となって壊れる部品が入っているとも思えない。
確実なのは、壊れているらしいということだが、さて困ったものだ。
正月前に妻がレンタルマンガで、宇宙兄弟を借りまくって読んでいたので、おれも読んだ。
おもしろい。最初はぐだぐだしていたが、選抜試験が始まると微妙に日常的なようでいて、全然違う世界があるし、それぞれの登場人物の背景やらそれから生じる行動と、他人との関係性の移り変わりとかが、極端な形で出てくるからだろう。
で、妻は、よほどおもしろかったのか、NHKのドキュメンタリー番組の書籍版を図書館で借りてきた。で、おれも読み始める。
やはりおもしろい。
ドキュメント 宇宙飛行士選抜試験 (光文社新書)(大鐘 良一)
むしろ、ノンフィクションなだけにおもしろさはより大きいかも知れない。
もっとも宇宙飛行士の就職試験+訓練ものという意味で先鞭をつけたのは途中で切られてしまったとは言え、やはり度胸星だよな。
ただ、よくよく考えてみると宇宙飛行士という職業が特殊(というよりも門戸が狭いというべきか)だからおもしろいのではなく、就職試験そのものが、それだけでおもしろいジャンルなんじゃないかという気もしてくる。(いや、おれが知らないだけで、ビジネスジャンプとかには、内定野郎一番星とか商社を狙えとかフリーター就職するとか外資狩りとかいった人気マンガがあるのかも知れないけど)
妻がロジクールマウスのセンターホイールが調子悪いと言い出した。
試してみると、確かにスクロールしたりしなかったりで調子が悪い。
カーソルやボタンクリックは普通に動くので、電池切れとも思えない。
しかし、買ってからそんなにたってないはずだし、壊れたとも思えない。しかし、もし壊れたのなら、結構気に入っているのでもう1個買おうかなぁとか予定していたけど、それは無しだよなぁ。
LOGICOOL ワイヤレスレーザーマウス Unifying対応レシーバー採用 M505 ブラック M505BK(-)
良くわからないので、とりあえず電池を見てみるかと、ひっくり返して裏蓋を開けて電池を抜いた。
すると、それまではどうにも見えなかったセンターホイールが結構良く見えることに気付いた。ということは、たとえば綿ボコリとかがひっかかっていたら、電池の挿入口から強く吹いたらどうにかなるかも、と気付く。
で、ふーふー息を吹き込んだら、でっかな綿ボコリが表から飛び出してきた。そうしたら、ちゃんと動くようになった。中でホコリがセンサーを邪魔していたのだろう。
なんで、そんなものが中に入ったかわからない(ことにしておくけど、表面についているのに気付かずにホイールをまわして中に押し込んだんだろうな)けど、とにかく、もしセンターホイールだけが不調になったら、裏蓋開けて電池出して吹いてみるという対処方法が確立されたのだった。
これまでDCOMのサーバとして動かしていたVB6のプログラムがあるのだが、ファイアウォールの向こうに設置する必要が出てきたので、Webサービスに変える必要が出てきた。
プログラムそのものは、1つのfrmと1つのclsから構成されていたのだがどうもfrmは使っていないらしく、単なる空っぽのフォームだ。外部COMサーバとして利用するから、とりあえず簡単に起動可能アプリケーションとするためにフォームを作ったのだろう。しかし、clsの中はなんかごちゃごちゃしたプログラムなので全面書き換えは避けたいところだ。
とりあえず、VS2010のVBに変換しようとしたら、なんとVS2010はVB6の変換ツールが搭載されていない。いや、まだVB6から移行していないユーザがここにいるのだが。とか思ったけどしょうがないのでしばらく困っていたが、VS2008をアンインストールしていないことを思い出して、VS2008を立ち上げたら、こっちには移行ツールが載っていた。で、変換しようとしたらエラーになる。参照しているCOMコンポーネント(これはDCOMではなくローカル)が開発PCに登録されていないからだ。しょうがないので登録してから変換する。このCOMコンポーネント(当然32ビット)は、運用ホストではそのまま利用することにする。
その昔、16ビットVBを32ビットVBに変換するツールがあって、これっぽっちも役に立たなかったのだが、さすがにVB6からVB2008への変換は問題なくできた。ディレクトリ構成が1段階なのは(今となっては)気持ち悪いが、まあ許容範囲だ。32ビットCOMコンポーネントを参照しているからか、.NETのコンパイル構成でターゲットはx86に固定されていた(Anyになっていたらおそらくはまるところだ。というのは運用サーバは64ビットWindowsだからだ)。で、そのプロジェクトをVS2010で読み込んでVS2010へ変換。
で、どうしようかとしばし悩むが、とりあえず、COM Interopに関する属性を削除して、単なるクラスに変えてみる。それから、WCFサービスを追加した。App.configに変更が入り、WCFサービスの実装ファイルとインターフェイスファイルが追加される。
次に、WCFサービスのインターフェイスファイルを元のclsだった名前にIを付けたものに変えてからメソッド定義を元のclsのほうからコピペした。そして元のclsのほうのメソッド定義をインターフェイス実装に変える。追加したWCFサービスの実装ファイルのほうは削除。
ここまでで、こんな感じになる。
'インターフェイスファイル Imports System.ServiceModel ' メモ: コンテキスト メニューの [名前の変更] コマンドを使用すると、コードと config ファイルの両方で同時にインターフェイス名 "IService" を変更できます。(注:IServiceはとりあえず追加したWCFサービスクラスの実装ファイル名Serviceから生成されたもの) <ServiceContract()> Public Interface IOnceComServer <OperationContract()> Function Hello(ByVal name As String) As String End Interface --- '実装ファイル(元はclsだったファイル) Public Class OnceComServer Implements IOnceComServer Public Function Hello(ByVal name As String) As String Implements OnceComServer.Hello Hello = "Hello " & name & " !" End Function End Class
App.configはざっくり大ナタを振るってserviceBehaviorだけ残す。この時点でWCFホストにするつもりだから本当はApp.Configはいらないのだが、httpGetEnalbedだけは既定で欲しいからだ。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name=""> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
それから、DCOMサーバだったときは全く意味がなかったfrmのほうに手を入れて、WCFサービスをホストできるようにする。
Imports System.ServiceModel Imports System.Net Public Class Form1 Dim host As ServiceHost Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim uri As New Uri("http://" & Dns.GetHostName() & "/VBService") 'ホスト名は、クライアントPCからのWSDL取得用HTMLに埋め込まれるので正しいものを設定する。 Dim binding As New BasicHttpBinding '認証とか不要なのでWSHttpBindingは使わない。 Try host = New ServiceHost(GetType(OnceComServer), uri) host.AddServiceEndpoint(GetType(IOnceComServer), binding, String.Empty) host.Open() Catch ex As Exception MessageBox.Show(ex.ToString()) End Try End Sub Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed If Not host Is Nothing Then host.Close() End If End Sub End Class
これで、HTTPポート共有が可能なら起動しておけば(疑問点: HTTPアクティブ化を使えば、起動しておかなくてもオンデマンドで起動できるのかな?)サービスリクエストをポート80で受けられる。(実行するサーバがWindows 2008 Serverの場合、役割の設定でアプリケーションサーバーのWebサーバー(IIS)サポート機能をインストールしておく必要がある)。
せっかくフォームがあるのだから、普段は最小化か通知エリア押し込みにしておいて、表示すると呼び出し回数とかメソッド平均実行時間とかの統計情報を表示するようにしておくと良いかも。
で、クライアントはサービス参照で、"http://ホスト/VBService"を指定して(ここではVBServiceReferenceという名称で取り込み)以下のようになる(面倒なのでC#で例)。
VBServiceReference.ServiceClient svc = new VBServiceReference.ServiceClient( "BasicHttpBinding_IOnceComServer", "http://" + 稼働ホスト名 + "/VBService"); MessageBox.Show(svc.Hello("boofoowoo"));
実行時にサービス参照したホストではなく、稼働しているホストに変えるのは、イントラネットでは当たり前(開発用サーバと運用用サーバは異なる)なのだが、例があまり出ていない。普通にあるユースケースだと思うのだがなぁ。しかもURIのホスト部だけを入れ替えられるようなコードを生成してくれれば良いのだが、自動生成されるServiceClientクラスのテンプレートには、ホストのみを交換できるコンストラクタが無い(ようにおれには見える)。そこで、エンドポイント構成名(「バインディングタイプ_インターフェイス名」の形式)とリモートアドレス(参照先のURI)を指定する。
実際は、クライアントもVB6のプログラムなのだが、同じくVB2010にVB2008経由で変換。で、CreateObjectしているところを上のサービス参照して生成したClientクラスの作成に変更。
それにしてもWCFについて調べるのは意外とやっかいだ。結構導入事例は多いと思うのだが、MSクラスターはどうも情報公開がいまひとつな気がする。
エッセンシャルWCF:Windows Communication Foundation (Programmer’s Selection―Microsoft .net Development Series)(Steve Resnick)やはり、このあたりは持っておくべきかも。(野村さんにもらったような気がするのだが、手元にはWPFとWFしか無いなぁ)
上野にベルリンバレエを観に行ったのだが、微妙に時間に余裕があったので、早めに行って国立西洋美術館でも寄るか、と子供を誘う。
何やってるの? と訊くので、しらねぇから調べてくれと答えたら、美術館のサイトを調べてなんか白黒のやつなんで興味ないとか言い出す。白黒ってなんだ? と覗くとデューラーの版画/素描展だった。
そうは言っても版画ってのは結構おもしろいし、この野郎は妙な題材を取り上げてるし(と、ギリシャ神話から題材をとった画をさして)いいじゃん、行こうと連れ出した。どうせ家にいてもだらだら過ごしてしまうわけだし、今ならお前は無料で観られるんだからラッキーじゃんとか。
そうしたら、むやみとおもしろい。
最初、版画で受難を題材にしたやつが、大きいの、ばらばらなの、小さいの、それから聖母伝とか、そういったのが並んでいる。おれは適当につまみ眺めしていたら(混雑はしていないが、精緻な作品が多いだけに列はゆったりとまるで草を食む羊のようにしか進まないからだ)、子供はしっかりと列の中に入ってじっと眺めている。気に入ったようだ。
乗り気じゃなかったわりにマジメに観てたじゃんと訊くと、そりゃ題材を良く知ってるからおもしれぇとか答える。最後の晩餐で皮袋を腰につけてるのがユダだよね、とか言い出すから、え、そりゃ気付かなかったと観直してくると、確かにユダ去りし後の1枚の不在の席に、他の2枚では腰に皮袋を下げた野郎が腰かけている。ああ、金貨の袋か、とか知ったかしたら、銀貨だよ、と修正されたり。
最初のやつには14人いたとか言うので数えると確かに14人いる。うーむ。ところで、イエスに抱かれている小僧は誰だ? と訊くと、そりゃ一番愛されているんだからヨハネに決まっているとか。すると顔回の役回りなんだなぁとか言ったらさすがにそれは知らないようだが、なかなかの教養人になっているようで、他にもお祈りのところとかいろいろ教えてもらう。なんでピラトが手を洗うんだ? と訊くと、日本語で言うと足を洗う+手を切るになるけど、せっかく余計な処刑をしなくてすむようにとりなしてやったのに民衆がそれを望むなら、おれは知らんという宣言の意味だとか。
だが残念。時間切れとなったので、次のフロアの素描とかはスキップせざるを得なくなった。で、駆け足で、想像で描いたという写実的でありながらまるでからくり仕掛けのような突起がある犀とか、不思議な建築物の形式のすごろくみたいなやつとか、布陣図のようなやつとか、眺めて、はて、メランコリⅡという画の前でこれはなんだか不思議だぞと立ち止まる。どっかで見たような。
そういえば、署名があれだよね、とか言い出すので確かに三角だし、技術者同盟人のような、とか、で思い出した。
子供に借りたロストシンボルでネタにされていたのだった。
というわけで、えらくおもしろかったので来週ちゃんと観ようとか決めたのだが、残念、1/16が最終日だったのであった。観られて良かった。
その他: 1490年あたりから活躍ってことは、以後涙の室町幕府なんだから応仁の乱のあたりの人だな。
また、グーテンベルクの直後の人なので、自身、民衆用の受難画の本を売りさばくべく小受難劇を出版するとか。おお、つまり、ニューメディアにすぐさま順応したアーティストってことだな、とおもしろく思う。
つまり、芸術的感動とか感慨のようなものとは無縁だが、大量の情報を埋め込んだ作品によって知的な興奮を与えるタイプの作家だった。機会があったら、こんだ、じっくり観てみたいものだ。
実践F#を読み進めているのだが、やっとOOPの章に辿り着いた。
ってこた、リストとタプルを使ったコードは書けるはずだな、と実戦導入についてちょっと画策。ちょろいインストーラあたりなら外れても影響無いし、いいかな。
実践 F# 関数型プログラミング入門(荒井 省三: いげ太)
以下、タイポ。
P.186 型推論と握手 → 悪手(駄洒落とは思えない)
P.221 7.8.2 項題にsumを追加
P.240 最初のリスト。それぞれemp, sglへ束縛するように打つべきだと思う
と、F#を読んでいるところに、正月っぽく山野さんから、獏をいただいた。
これは、オライリーの実践側(実践Rubyとか、Real World Haskellとか)の真打ちだから、Scalaの紹介フェーズが終わって、アーリーアダプターが実戦投入(今は未だイノベーター支配期だとおれは見ている)しようとしている今にふさわしいタイミングだと思う(つまり、イノベーターが実戦投入し終わった振り返り期なので、こういう書籍が出て来る)。DSLとしての利用やアプリケーション設計についての独立した章がある。バージョンは2.7メインだけど、2.8について訳注や補章を入れてある。
章立てで気付くのはOOが関数より先に来るところ(章数も多い)。こういうのは些細なことだが、ちょっとした意外感があるので、F#のほうを読んでいるから細かく読むのは後回しだけど、読むのが楽しみだ。
後、水島さんがチェックを入れたそうなので、訳には問題ないと思う。
そして、達人出版会から、はじめる! Squirrelをいただく。
まだ、全く読んでないから内容についてはわからないけど、Luaに乗り損なったゲームスクリプターならこっちに乗ってみるのがおもしろいんだろうと思う(と、Luaオルターナティヴ言語だと、おれは考えてるんだけど、実際のところはわからない)。
なんか良くわからんけど、おそらくJDBCのResultSetあたりから自動的にHashMapを作るものらしきユーティリティークラスがあって、そいつのコンストラクタを呼ぶ場所がこんな感じになっている。
String[] props = new String[] { "a", "b", "c", ..... }; // カラム名らしい。 RSUtil rsu = new RSUtil(props);
とりあえず、これについてはまあ良いとして、そしてpropsが50要素くらいあるのもまあ承知しているし、かつそこに追加で20要素くらいおれが付け加えるというのも良いだろう。
が、一体どこで詰め込みしているんだ? と追っかけると、とんでもないものに出会った。
(ちょっと大げさに表現すると)
String sql = "select ";
ああ、と、ここまで読んで、これからえんえんとpropsの50要素をループで詰めるんだなと想像して、StringBufferとかにしようか、いや、固定数だからそのままにしておこうか、とか思いながら下を読む。
sql += " nvl(a, ' '), "; sql += " nvl(b, 0), "; ... (スクロール2回分) sql += " from "; sql += TABLE_NAME; sql += " where "; ...
わが目を疑うこの惨事。(スクロール2回分のところには「ほぼ同上」な行が)50行続くのだな、これが。
えーと、さっきあったpropsっていうのは一体なんなんだ?
いや、答はわかっている。nvlをぐにゅぐにゅとかもごるんだろう。
ならば、こうすりゃいいじゃん。
String[] options = new String[] { "' '", "0", .... }; ... assert props.length == options.length; for (int i = 0; i < props.length; i++) { sql += " nvl(" + props[i] + ", " + options[i] + "), "; } // バグがあるから、続く
いや、本当はこれでも不快なのだが、それでも50行えんえんと(しかも、おれはそこにさらに20行も追加するのか?)並べるより200光年くらいましだ。
というよりも、おれが真にぞっとするのは、不快感と恐怖に襲われてめまいがしてくるのは、このコードを打ち込んだやつは、ひたすら、最初のsql += " nvl(a, ' '), ";
をコピーして50回ペーストして、ひたすら、a
と' '
を黙々と変更していたのだろうという、その底冷えのする仕事風景なのだ。(自動生成ですらないのは、それっぽい元ネタやスクリプトが残っていないから間違いなかろう。おそらくpropsの配列の中身も何かをひたすら写経したのであって、Metadataから生成したとかではあるまい。というか、Oracleなのに全部大文字ではないから、写経以外とは思えない)
その作業風景は、まさにコーダーという言葉から想像される職業の人そのものだ。どこにも意思決定のかけらもない、機械的な繰り返し作業だ。吐き気がする。
今、文字列の配列 array = { "a", "b", "c" ... "z" }があって、ここから、"a, b, c, ..., y, z"というカンマ区切りの文字列を作るとする。
C#なら、何も考えなくとも、string.Join(", ", array);で出来てしまうが、Javaには今のところそういうメソッドはStringにもArraysにもない。この2つになければきっとないだろうと思う。
C#だって、zipしながらじゃできないのではなかろうか。と思ってSystem.Arrayクラスを眺めていたらAsReadOnly
で、最近はString#+が賢くなったので、StringBufferとかStringBuilderとかをあまり使わないような気がするのだが、カンマ結合のときは、非常に便利なので良く使う。
というのは、
String[] a = new String[] { "a", "b", .... }; String cvs = ""; for (String s : a) { if (cvs.length() != 0) { cvs += ", "; } cvs += s; }
みたいな、どうでも良いループの中で、たった1回切りしか意味がない条件節を入れるのが不快だからだ。無駄なことこのうえない。
それに対してStringBuilderみたいなものを使えば、安価に記述できる。
String[] a = new String[] { "a", "b", .... }; StringBuilder cvs = new StringBuilder(); for (String s : a) { cvs.append(s).append(", "); } cvs.setLength(cvs.length() - 2); // もちろん最低でも1要素は存在する前提。0要素があるなら、ここでcvs.length > 0 すれば良い(ループの外に条件節を入れるのは不快ではない)
でも、最近、別解もあるなぁと、少なくともSQLを文字列組立しているときは思う(が、上のように書くので通常は使わない)。
String[] a = new String[] { "a", "b", .... }; StringBuilder sql = new StringBuilder("select "); for (String s : a) { sql.append(s).append(", "); } sql.append(" 0 as DUMMY from ").append(TABLE_NAME);
カンマが余分なら、要素を追加してやれば良いのであった。
病院とかの待合用にちょびちょび読んでいたサケッティの巷談集を読了した。
ルネッサンス巷談集 (岩波文庫 赤 708-1)(フランコ・サケッティ)
なんというか、実にくだらないのだが、まあ、おもしろかった。
これは14世紀から15世紀にかけて、フィレンツェ自由都市で適当に(しかし断固として自由人としての尊厳を持ち)暮らした一人の市民が書き残した(経緯を前書きやら解説で読む限り、私家版のおもしろ小説集という感じで、聞いた話や見た話なんかをちょこまかまとめて、友人たちに読ませたものが、一部残っていたということらしい)市民生活の断片集のようなものだ。元禄畳奉行の記録とかに近いというか、むしろ内容の適当さはBlogやWeb日記みたいなもんだな。
というわけで、だいたいの話は、まだ生きているが市民なんちゃらが若い頃、とか、我らが愛すべき大画家ジョットがある日のこと、とか、おれがこないだ市民誰それと市場に行ったとき、とかそんな感じで始まる。
で、どのような話かと言えば、だいたいはこんな感じとなる。(名前とかは適当)
尊敬すべき司祭誰それは、貧乏人ばかりの教区に赴任したのは良いが、あいつの舌鋒は常に貪欲と奢侈に鋭いから、常に倹約の美徳について語り飽食と贅沢をいましめるものばかりだ。かくして、我が愛すべき貧乏人の中の貧乏人、市民なんちゃらは3回目の説法のときに立ち上がって言った。おえらい司祭様、あんたの話はさっぱりわからない。贅沢ってなんのことですかい? 飽食とは? 観ての通り、ここに集まっている連中とは縁の無い話ばかりですな。司祭は深く恥じ入り、以降は貧乏人こそ幸いであるという話をするようになった。
もっとも、これは例外的にまともな(反省するからだが)司祭だが、ほとんどの話において司祭や司教が出てくれば、それは嘘つきで見栄坊のくずばかりで、最後には必ず、というわけで教会というならずもの集団によって主の栄光は今や地に落ちんばかりである、と結ばれる。
あるいは、王党派に対するこき下ろし。偉大な詩人ダンテ(詩才については持ち上げる)が、いかに下劣な政治意識の持ち主かを糾弾し、これだから王党派は人間の尊厳を捨て去ったゴミのような連中である、となる。
批判の的は、法律家にも向けられる。ボローニャで法学を学んできたなんとか氏の甥がえらそうに法律を振り回すので、他の市民から父親は「お金と時間をドブに捨てた」と馬鹿にされるとか。あるいは他の市から来た自由人が、フィレンツェ自由都市には3人しか弁護士がいないと聞いて祝福を与え、しかし、それにしても惜しい。自由が3人分は損なわれているとは、とみんなで嘆くとか。
つまり、自由市の自由人たちにとって、宗教家と法律家と王制派は唾棄すべき存在で、彼らの行動はこれすべて愚者の行いとして笑いのネタにされる。
そして全体の20%を占めるエロ話。ブドウ畑で怪しいことをしているのでブタやらロバやらをけしかけて裸で逃げるさまを笑いものにしたりとか。
中にはこったものもあって、亭主に言い寄られて困るという後家さんの愚痴を聞かされた女房、後家さんに万事わたしに任せとけと請け合い、亭主に承諾するように告げる。亭主が後家さんの家に出かけるのを見届けるや、後家さんと入れ替わりに寝室で待つ女房。ところが亭主は友人を見張りに連れてくる。ちょっと待っててくれと4回やって戻ってきて、おまえもちょっと行ってみろよ、とか。翌日女房、亭主にあんたには7回の貸しがあると告げる。最初亭主は何のことかわからない。すると女房、得意げに最初4回、次に3回と言う。そこで亭主、何も言えずに以後おとなしくなる。一方友人(女房もだろうけど)は最後まで自分は後家さんと遊んだつもりになっているとか。
あるいは、傭兵の逸話。イギリス人の傭兵隊長のところへ坊さんが3人寄進を求めに行く。結構な額にありつき、感激して「平和があなたの上にあるように」と祈ると、隊長いきなり怒り出し「おまえらの寄進がすべて失われるように」と言う。平和になったらおれは失業するじゃないか。だからお返しに同じ目にあうように祈ったのだ。坊主たちは平謝りに謝り、「戦争が常にあなたと共にあらんことを」と祈る。やれやれ(とサケッティは肩をすぼめる)、まったく自由には平和が必要ということが良くわかりますね。こんなくずどもに好き勝手されてるようではまだまだですよ。(すべての話の最後には、必ずサケッティ自身によるその話に対する寸評が入るのである)
あるいは金持ちに土地を少しずつ奪われて、ついに最後となったときに、寺院の鐘という鐘を鳴らし「正義は死んだ」と宣告して回る農民の話(何事かと驚いた参事によって、無事、正義は生き返ることになる)。
数が多いだけに、しかも聞き書き、体験談なので、似たような話がたくさん(市場でロバが暴れてけんかになるとかだけで3から4回は出てきた)、機知に富んでいたり軽妙なやりとりがおもしろいものもあるが(特にメディチ家の人間と当時フィレンツェに屈服した近くの封建領主の息子のやりとりは3、4回出てくるが、まるで世説新語の孫晧と司馬炎のやりとりみたいで滅法おもしろい)、また坊主の悪口か、というようにうんざりするようなものもたくさん。
一方、日本では金閣寺を建てていた。
上野でマラーホフ率いるベルリンバレエのチャイコフスキー。
最初は5番で、死の床、分身とじゃれあい、(カラボスらしいが良くわからなかった)、白と黒のオディット/オディールなのかロットバルトなのか(黒鳥は全員男)、ドロッセルマイヤーと水色のくるみ割り人形。
次は良く知らない軽快な曲で、テーブルが舞台で、妻と男たち、フォンメック夫人から札束を投げつけられて、それを妻に投げつける、スペードの女王、賭博者(という作品はないけど、そういえばドストエフスキー的だ)、6番のアダージオ、拘束衣を着せられて頭を刈られた妻、死んだ。(弦楽セレナーデは当然のように最初の下降するとろこを使うのかと思ったら違った)
圧倒的な表現力。持続する体力。すごいなぁ。
年取ると、感覚は鈍るというものだと思っていたが、実は違うのではないかという気もする。
明らかに、遠視が入ってくるから視るモノについては衰えたと言い切れる。あるいは、蚊が飛ぶ音みたいなやつは、まったく聴こえないから、これも可聴音域が狭くなったと言えるだろう。
ところが、味覚(実際には舌はほとんど大した感覚がなく、嗅覚の影響が大きいらしいので、その意味では嗅覚かも知れない)については違う。鹹味と甘味については鋭敏になっている(というのは、以前だったらあり得ないくらいの少しの味付けで十分にそれが機能するし、子供の頃だったらほとんど味を感じない=まずい野菜というような位置づけだった白菜やら水菜やらが実にうまく感じる)ように思える。
しかし、機能的に加齢によって味覚だけが鋭くなるということは考えにくい。
その一方で、味覚の大家は海原雄山のような老人と昔から相場が決まっている(印象論ではなく、実際にそうなんだろうと思う)。ひとつは、いろいろうまいモノを食ってきたので黒白つけやすくなっているとか、基準点を確立しているといったことはあるかも知れない。しかし、それだけでは若い感覚に勝てることはないだろう。だから別の何かがあると考えるほうが自然だ。それにしても、通念として老人はあっさり味が好みとされているが、そうではなく、若い調理人にはあっさりしていると感じる味付けの中に深い味わいを得ているというのが真相に思える。
そこで、次のような仮説を立てた。
蚊の音のような高周波ということで、ケータイの若者にはちゃんと言葉が聞こえるが老人(中年も含まれるように思う)には聞こえないというやつが出回っていて、妻と子供が遊んでいたが、どうも、逆に子供には老人が聞こえる音は聞こえていないようだ(なので、遅回しによって示す必要がある)。
ということは、高周波(というよりも人声というわかりやすい音)によりマスキングされているということではなかろうか。それによって老人が聞こえる音が聞こえない。
鹹味と甘味に対して子供になればなるほど鋭敏で、それにより他の雑味がマスキングされてしまう。そのために微妙な味わいを感じることができない。その結果として深い満足を得ることができないために、さらに鹹味や甘味を強調した味付けを求めてしまい、ますます雑味をマスクしてしまい単純な味を感じ取る。
それが加齢によって鹹味や甘味に鈍くなることでマスキング効果がなくなり雑味をはっきりと感じ取ることが可能となる(その一方で、他の味(あるいは香り)と混合されることで、微量であっても鹹味や甘味を検出できる)。そのため、老人のほうが料理の深い味わいを楽しめる。
つまり、この季節は白菜がうまいし、鱈の鍋とか子供の頃はまったくうまいと思わなかった食い物がうまい。
さくらインターネット研究所のセミナールーム。
電源と無線LAN完備で、申請ー承認で無料というのはすごい。場所は角筈、アスキーの近く。
Azureに対するODataはマルチパートマイム(カタカナで書くとすごいな)でトランザクションだそうだ。WCF Data serviceも同じか調べてみよう。追記:多分大丈夫そうだが試すのは難しい。
その他いろいろ。
追記:間違ってるところを修正。yfakariyaさんのコメントも参照
昨日、同僚と例外を出しまくるテストをしていて恐ろしいことに気付いた。
次のようなメソッドをクラスライブラリで用意したのだった。
public int Foo(string s) { // たとえば try { var m = KEYWORDS.match(s); if (m.Success) { return int.Parse(m.Group[1]); } } catch (Exception e) { var b = new StringBuilder("argment is ok ?\r\n"); b.Append("value=").Append(s); Logger.Write(e, b.ToString()); // LoggerはeのStackTraceプロパティをログする。 throw new ArgumentException(b.ToString(), e); } } .... public void Write(Exception e, string s) { ... logWriter.WriteLine(e.StackTrace); ... }
おれの作ったクラスライブラリは、Java流儀というか、引数のnullチェックみたいなくだらないことはしない。そういうものは下位のクラスライブラリに任せる。したがってnullが与えられるとRegex.MatchがスローするArugmentNullExceptionを取る。(さすがにこれは例が単純過ぎるが、本来はいろいろな例外が引数によって発生する可能性がある)
しかし、ライブラリのユーザがまじめに例外を処理することはあまり期待しない。すればOKだがしなくてもそれはその時だ。そこで、後で原因がわかるようにこちらで例外を受けたらログをするわけだ。
で、そうやってnullを与えたりその他の(上の例だとちょっと他の例は考えにくいが)エラーになるパターンを与えたりしてログにさんざん書き込んだ。
で、ログを見てびっくり。
スタックトレースのボトムが、Foo(String s)になっているからだ。
このトレースみたら、悪いのはFooメソッド以外に存在しないことになってしまう。
そこでいろいろ試すと、どうも、アセンブリ境界(.NET Frameworkのアセンブリの直前のアセンブリの最初のメソッド)でスタックトレースが切られてしまうようだと気付いた。
いや、これはクラスライブラリを提供する側にとっては致命的だよ。誰が呼び出したかを調べるためにトレースを残そうとしているのに、それが残らないわけだから。
で、気づいて良かった良かったということで、ロガークラスのほうで
var st = new System.Diagnostics.StackTrace(1); // 0にするとロガーのこのメソッドになってしまう logFile.WriteLine(st.ToString());
と書き出すようにして決着。
が、今、追試してみて、確かにアセンブリ境界で切れるようだと確信したが、どうしてこんな愚かな仕組みになっているんだ?(追記:メソッドの位置の問題で、アセンブリの境界ではなく、スロー元からキャッチしたメソッドまでを取り出すようになっているため、そのように見えていたということで、誤り) と疑問は拭えない。おれの設定とかがおかしいんんじゃないかという気がするわけだ。
追記:さらにいろいろ試すと、System.Diagnostics.StackTraceはフレームの位置を決められるというメリットはあるけれど、行番号をまったく残してくれないことに気付く。とすると、Environment.StackTraceのほうが行番号が付くから良いかも(しかし先頭2つがEnvironmentになってしまうのがいやな感じだ。というか、PDBファイルを置かなければいずれにしても行番号は無いはずだから、Diagnosticsのやつでも同じかなぁ。
追記:matarilloさんからのツッコミを受けて、Backyardへ修正版を作成。というわけで、以下でInnerExceptionとアプリケーションログの関係について記述しているところは正しくはありません。
昨日は、yfakariyaさんやmatarilloさんからいろいろ指摘を受けたので、あらためてMSDNを読んでExceptionクラスが返すものをチェックしてみた。
結論から言うと、アプリケーションとライブラリでは同じExceptionオブジェクトでも(少なくとも後からの調査用のログという観点からは)見るべきプロパティを変えるべきだ。
以下のテストプログラムを用意した。
Fooメソッドは呼び出し先メソッド(当然ライブラリを想定する――アセンブリの違いというのは全くの誤解釈だとわかったので同一クラスでも良い)を信用していない。したがって、このメソッドが採取すべきログは呼び出し先の振る舞いを調べるための資料となるものだ。
Bazメソッドは呼び出し元メソッド(当然アプリケーションを想定する)を信用していない。したがって、このメソッドが採取すべきログは呼び出し元の呼び出し条件を調べるための資料となるものだ。
using System; using System.Text.RegularExpressions; public class Exp { static readonly Regex KEY = new Regex("^(\\d\\d):.+$"); bool withE; public Exp(bool e) { withE = e; } public void Foo() { try { Bar(); } catch (Exception e) { Console.WriteLine("in Foo:"); PrintException(e); } } void Bar() { Console.WriteLine(string.Format("key={0}", Baz(null))); } public int Baz(string s) { try { var m = KEY.Match(s); if (m.Success) { return int.Parse(m.Groups[1].Value); } else { return -1; } } catch (Exception e) { Console.WriteLine("in Baz:"); PrintException(e); if (withE) { throw e; } else { throw; } } } void PrintException(Exception e) { Console.WriteLine("ToString: " + e.ToString()); foreach (var p in e.GetType().GetProperties()) { Console.WriteLine(string.Format("{0}: {1}", p.Name, p.GetValue(e, null))); } } public static void Main() { var e = new Exp(false); e.Foo(); Console.WriteLine("---------------------------------"); e = new Exp(true); e.Foo(); } }
最初の呼び出しと次の呼び出しの差は、ライブラリが例外をスローする場合に、暗黙の再スローか明示した再スローかだ。というか、昨日までは暗黙再スローの存在はまったく知らなかった(10年前には言語仕様を読んでいるから忘れたのだと思うが、覚えていなければ知らないのと同じ)。
出力は以下となる。サーバーサイドではないのでPDBはデプロイ対象としていない状態を想定する。
c:\Users\arton\Documents\test>Exp in Baz: ToString: System.ArgumentNullException: 値を Null にすることはできません。 パラメーター名: input 場所 System.Text.RegularExpressions.Regex.Match(String input) 場所 Exp.Baz(String s) Message: 値を Null にすることはできません。 パラメーター名: input ParamName: input Data: System.Collections.ListDictionaryInternal InnerException: TargetSite: System.Text.RegularExpressions.Match Match(System.String) StackTrace: 場所 System.Text.RegularExpressions.Regex.Match(String input) 場所 Exp.Baz(String s) HelpLink: Source: System in Foo: ToString: System.ArgumentNullException: 値を Null にすることはできません。 パラメーター名: input 場所 System.Text.RegularExpressions.Regex.Match(String input) 場所 Exp.Baz(String s) 場所 Exp.Bar() 場所 Exp.Foo() Message: 値を Null にすることはできません。 パラメーター名: input ParamName: input Data: System.Collections.ListDictionaryInternal InnerException: TargetSite: System.Text.RegularExpressions.Match Match(System.String) StackTrace: 場所 System.Text.RegularExpressions.Regex.Match(String input) 場所 Exp.Baz(String s) 場所 Exp.Bar() 場所 Exp.Foo() HelpLink: Source: System --------------------------------- in Baz: ToString: System.ArgumentNullException: 値を Null にすることはできません。 パラメーター名: input 場所 System.Text.RegularExpressions.Regex.Match(String input) 場所 Exp.Baz(String s) Message: 値を Null にすることはできません。 パラメーター名: input ParamName: input Data: System.Collections.ListDictionaryInternal InnerException: TargetSite: System.Text.RegularExpressions.Match Match(System.String) StackTrace: 場所 System.Text.RegularExpressions.Regex.Match(String input) 場所 Exp.Baz(String s) HelpLink: Source: System in Foo: ToString: System.ArgumentNullException: 値を Null にすることはできません。 パラメーター名: input 場所 Exp.Baz(String s) 場所 Exp.Bar() 場所 Exp.Foo() Message: 値を Null にすることはできません。 パラメーター名: input ParamName: input Data: System.Collections.ListDictionaryInternal InnerException: TargetSite: System.Text.RegularExpressions.Match Match(System.String) StackTrace: 場所 Exp.Baz(String s) 場所 Exp.Bar() 場所 Exp.Foo() HelpLink: Source: System
以上からわかることは、catchしたExceptionオブジェクトから得られるスタックトレースは、StackTraceプロパティのものであろうがToStringメソッドのものであろうが、併設したtryブロックから先だけだということだ。
これはアプリケーション(ライブラリを信用していない)にとっては十分な情報量だ。しかも最低限に必要と考えられる情報(Messageプロパティの値とStackTraceプロパティの値)はすべて単一のToStringメソッド呼び出しで得られる。
つまり、アプリケーションが例外をログするのであれば、ToStringの結果をログすれば良い(InnerExceptionチェインがnullになるまでToStringすればもっと良い)。
それに対して、アプリケーションを信用しないライブラリにとっては話が異なる。
信用していないのだから、アプリケーションプログラマに対して、このメソッドの呼び出し(またはそのメソッドを呼び出したメソッド……)はおかしい(引数がおかしいのか、状態がおかしいのか、いずれにしろ事前条件相当のものは例外とは別にログする必要はある)と指摘できなければならない。そのためには、別途スタックトレースを入手する必要がある(Diagnostics.StackTraceとか)。
それだけではなく、アプリケーションに例外をスローする場合には次のいずれかを利用すべきということも言える。
1: 独自にArgumentException(事前条件のうち引数違反)やInvalidOperationException(事前条件のうち状態違反)を作成し、InnerExceptionにキャッチしたExceptionオブジェクトを設定する。ただし、アプリケーションを信用していないのだからInnerExceptionがアプリケーション側でログされることは期待できない。したがって2:のほうが良い。
2: 暗黙の再スロー(無引数throw)。キャッチしたオブジェクトを指定した再スローでは真の原因(上の例ではRegexが検出した引数null)の通知元がTargetSiteプロパティにしか残らない。すると、上で示したようにアプリケーションはToStringの結果だけをログするとした場合に、真の原因が不明となりライブラリ側の調査が難しくなる可能性がある。
ジェズイットを見習え |
_ arai [P.172の<-ですが、P.87「4.8 可変な変数」で出てきたmutableな変数への代入になります。 索引に関し..]
_ arton [どうもありがとうございます。再代入演算子というところですね。白い囲みだけ読み返したのが見つけられなかった原因でした。]