今年最初の読書: .net や C# について書籍を当たってみた

(少し遅くなりましたが)あけましておめでとうございます。

実家から筑波への帰りに、新宿駅近くの紀伊國屋書店に行ったところうっかり書籍を大量に買い、そのまま帰宅したところ風邪気味なのも相まってうだうだとしていたのでした。

そこで買った書籍のうち、特に重量があった洋書が以下の二冊。

Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (Microsoft Windows Development Series)

Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (Microsoft Windows Development Series)

Annotated C# Standard

Annotated C# Standard

Framework Design Guidelines

乗り物酔いせぬようにざっと流し読みした限り、前者の "Framework Design Guidelines" は、.net framework 3.5 上でフレームワークやライブラリを作る上での注意点などを、

  • DO
  • SHOULD
  • CONSIDER
  • DO NOT
  • AVOID

といった語のどれかで始まるガイドラインになるようにまとめた本なようだ。

ガイドラインは、.net framework についてある程度の知識があれば十分理解可能なわかりやすさを持ちながらも、.net framework 上の各種クラス群などがどのような意図で設計され、どのように振る舞うのかといった事柄をきちんと考慮した上でガイドラインが述べられている。
ので、単なるお約束集としてだけでなく、.net framework への理解を確かなものに近づけるためにも有用そうである。

しかも、本文や注釈の著者も、.net frameworkC#, VB などの設計に深く関わっているメンバーばかりで、「これこれのクラスは元来はこういう意図のものであって、こうするためのものではない」といった歴史的事情を踏まえた説明や、時に「.net framweork のこれこれのクラスは、これこれのまずい例である」といったツッコミなども入っており、すでに知っているガイドラインであっても楽しめる内容であったので、ハードカバーをどうにか家まで持ち帰った甲斐があったものである。

例えば、"DO NOT throw or derive from System.ApplicationException" については

JEFFREY RICHTER
System.ApplicationException is a class that should not be part of the .NET Framework. The original idea was that class derived from SystemException would indicate exceptions thrown from the CLR (or system) itself, whereas non-CLR exceptions whould be derived from ApplicationException. However, a lot of exception classes didn't follow this pattern. For example, TargetInvocationException (whitch is thrown by the CLR) is derived from ApplicationException. So the ApplicationException class lost all meaning. The reason to derive from this base class is to allow some code higher up the call stack to catch the base class. It was no longer possible to catch all application exceptions.

という注釈が付いているといった案配である

注釈が 2 ページ辺り 3 個ほど付いているのもあって、ガイドラインそのものは簡潔かつ平易ながらも、書籍全体としてはかなり濃厚である。
ので、特にライブラリやフレームワークをいじる機会があったり、あるいは純粋に CLR などに興味があるならば、値段相応の価値があると感じられる一冊であった。

参考までに: 上の注釈(英文)の概要

意訳すると、こんな感じであろう。

System.ApplicationException は .NET Framework に含まれるべき class ではなかったのである。そもそも、CLR やシステムそれ自体が発生させた例外は SystemException やその派生型で表され、CLR 本体以外が投げた例外が ApplicationException の派生型として扱われる、という発想だったのである。

しかしながら、(.NET Framweork の)多くの例外 class はこのパターンに沿っていない。例えば、(CLR から throw される例外である) TargetInvocationException は ApplicationException を継承してしまっている。そのため、ApplicationException の意義が台無しになっているのである。

そもそも、(CLR 本体以外が投げた例外が) ApplicationException を継承する目的は、call stack の上の方に位置する何らかのコードが ApplicationException を catch するためであった。しかしながらも、(call stack の上位のコードが) ApplicationException を catch することで、アプリケーション(= CLR 本体以外)が投げたあらゆる例外を処理する、ということは出来なくなってしまったのである。

ちなみに、ApplicationException クラス (System) には、

致命的ではないアプリケーション エラーが発生した場合にスローされる例外。

ApplicationException は、共通言語ランタイムではなく、ユーザー プログラムによってスローされます。デザインしているアプリケーションで固有の例外を作成する必要がある場合は、ApplicationException クラスの派生クラスを生成します。ApplicationException クラスは Exception を拡張しますが、新しい機能は追加しません。この例外は、アプリケーションで定義された例外とシステムで定義された例外を区別する手段として提供されます。

といった記述がなされているようだ。

C# Annotated Standard

一方、こちらの書籍は、ISO 23270:2006, Ecma International Standard 334 version 4 in June 2006 の errata 修正済み全文に注釈を付加した(Annotated)ものであるとのことだ。これらの標準規格では C# 2.0 について述べられているので、書籍の内容も C# 2 についてのものになっているようだ。

また、この書籍の注釈では、VisualStudio 2005 や Mono 1.2 の実装や、C# / CLI 規格外の各種拡張についても随時述べられている。例えば、

public static void Main(string[] args) {
	int G = 1, A = 2, B = 2;
	int blah = F(G < A, B >> 7);
}
public static int F(bool a, int b) {
	return 47;
}

というコードは、C# 2.0 的には F( G と A の大小比較, B の右シフト ); になるはずが、VS 2005, Mono 1.2 双方でコンパイルエラーになる、といった話である。ちなみに、筆者の環境の VisualStudio 2008 の場合、IntelliSense は正しく動かない*1が、コンパイルはちゃんと通っているので、新しい csc *2では治っているようである。

上記の事柄のみならずとも、分かっているようで分かっていなかった部分や、C# 1 と 2 の差異といった興味深い内容も書かれているので、それらは随時エントリに書いてゆきたいと思う。

Saiya としては、ECMA の頒布している pdf を延々とプリントアウトして泣きながらめくらなくても良いだけでも嬉しい書籍なのだが、注釈だけでも(家まで持って帰る手間を含めた)コスト相応のものがあって、良い買い物であった・・・。

*1:正しく動く IntelliSense というのも想像が付かない。Generics 型 G が存在して、かつメソッド F がオーバーロードを持っていたりするという状況を考えると、いよいよもって C# なコードを左から右に書くことの問題を感じる。他にもメソッドの宣言の戻り値型などについても、Generics と IntelliSense の相性はどうにも微妙である・・・。

*2:C# コンパイラ