.NET の利点の一つは言語間の相互運用性だ。
「言語間の相互運用性がある」とは CLS(共通言語仕様:Common Language Specification) に準拠しているという事である。(準拠していなくても可能ではあるが)
CLS について、どうにも腑に落ちない点があった。次のコードを見て欲しい。
[CLSCompliant(true)]
public class NoCLS
{
public Int32 GetInt()
{
return 1;
}
public int Getint()
{
return 1;
}
public UInt32 GetUInt()
{
return 1;
}
public Guid GetGuid()
{
return Guid.NewGuid();
}
}
このクラスは CLS 準拠ではないのでコンパイルエラーになる。何が準拠でないのだろうか。
1.大文字小文字の区別だけでメンバを定義できない。
GetInt() と Getint() の事だ。
2.UInt32 を使っている。
実はこれが腑に落ちない所である。後で述べる。
この他にも CLS に準拠するには沢山のルールがある。詳細はドキュメントを参照されたし。ちなみに、Getint() を削除すると、GetInt() は CLS 準拠にはなる。コンパイルエラーにならない。しかし、名前付けが CLS 準拠ではない。
「Int」という特定の言語に縛られる名前を使ってはいけないのだ。この場合は、GetInt32 という名前が宜しい。名前自体が CLS 準拠かどうかは人間しか判断できないので注意が必要である。例え CLS 準拠として公開できても、そんなものは半準拠だ。
さて、何故 UInt32 を使う事がが CLS 準拠ではないのか。特定の言語(例えば Visual Basic 7)に符号なし整数が存在しない事が原因だ。なるほど、確かに合点がいく。
しかし、ここで少し考えてみて欲しい。「言語に符号なし整数が存在しない」とはどういう意味だろうか。
C# を例に挙げるが、そもそも C# 自体には何も「型」が存在しない。int は Int32 のエイリアスだと謳っているし、uint は UInt32 のエイリアスだ。そういう意味では C# には「符号あり整数すらも存在しない」のではないのか?そして、Guid は何故 CLS 準拠なのだ?そんな型が存在する言語は思いつかない。UInt32 が CLS 非準拠ならば Guid も CLS 非準拠なはずだ。何故 UInt32 が NG で Guid が OK なのか。この二つの違いは何なのか。UInt32 には、「[CLSCompliant(false)]」属性が付いているから非準拠になってしまうわけだが、何故あえてこの属性を付ける必要があるのか?.NET Framework クラスライブラリのクライアントから見れば、Guid も UInt32 も同じアセンブリにあり、同じ名前空間にあるただの構造体だ。
確かに Visual Basic 7 では UInt32 に値を入れる事が難しい。
Dim a As UInt32
a = 1
上記が不可能なのだ。「1」が Integer(Int32) だとみなされてしまうからである。
Dim a As UInt32
a = Convert.ToUInt32(1)
上記のようにすれば可能だ。つまり UInt32 を使う事は可能なのである。Convert.ToUInt32() が CLS 非準拠だって?それは UInt32 が CLS 非準拠なっているからだ。そもそも UInt32 を非準拠にする理由が見当たらない。
待てよ。答えは「リテラル値で表現できるかどうか」なのか?
確かに、 Visual Basic 7 は符号なし整数をリテラルで表現できない。これが「Visual Basic 7 には符号なし整数が存在しない」という事なのだろうか。
そういう意味では C# には「符号あり整数型」や「符号なし整数型」は存在すると言える。つまり、CLS 準拠な型とは、あらゆる言語がリテラルで表現可能な型、もしくはそれの集合となっている型という事なのだろう。
.NET を語るときによく聞く「int すらも実は他の型と同じようにクラス(構造体)なのだ。C# の int や VB の Integer は Int32 のエイリアスだ。他の型と区別なんて全くないのだ」というのは、考え方が単純化されて、ある意味では正解だが、深く考えると少々違う事が分かる.
言語には、間違いなくプリミティブ型というものがあり、それが無ければ何も表現できない。int が Int32 のエイリアスなく、Int32 は各言語のプリミティブ整数型を包んでいるラッパーなのだ。そして言語のプリミティブ整数型が IL の整数型に一致するように、各言語のコンパイラは作られている。
CLS がコンパイラに求めているのは、符号あり整数などのいくつかのプリミティブ型であり、CLS が型設計者に求めているのは、それらプリミティブ型のみ、もしくはその集合のみ使用するという事なのだろう。Guid はそれに適合する。