.NET を理解する5
ジェネリックコレクション
ジェネリックコレクションは、System.Collection.Generic に存在する、Generic 機能を利用したコレクションクラスです。
これは、対応する非ジェネリックコレクションに比べて、タイプセーフかつ高速に動作します。
これには
- List
- Dictionary
- Queue
- Stack
- SortedList
- SortedDictionary
等があり、これらは非ジェネリックのそれぞれのクラスに対応します。
実装の違い
Generic を理解し、Collection を知っていれば、使うことは難しくないでしょう。
ここでは、同じ Generic を持つ Java と、元となった Template を実装する C++ とを比較してみます。
1.実装方法
これは明らかに差があります。
- C#(.NET) : Generic の為の拡張命令をアセンブリに持ちます。object 型へのキャスト等の処理が行われない為、高速です(C++には負けますけど、、、)。
- Java(JVM) : Java5 ではコンパイラのシンタックスシュガー(糖衣構文)で実装されます。object 型への変換、元の型へのキャストを、暗黙的に埋め込みます。実行速度は従来のものと変わりません。
- C++(ネイティブ) : typedef や define マクロ同様に、コンパイル時に型を埋め込む形でコンパイルします。実行速度は最速ですが、ファイルサイズが大きくなる、ライブラリをソースで配布するしかないという欠点もあります。
2.型安全性
- C# : Generic 指定の異なる型は、完全に違う型として認識されます。継承関係のある型のジェネリックに関しては、.NET4.0 以降でジェネリック型のキャストが可能です。
- Java : Java6 以降でかなり進化しました。コンパイラレベルでチェックされ、互換性のない型を弾けるようになっています。
- C++ : 完全に別の型としてコンパイルされます。
3.互換性
.NET3.5 からは、下位のライブラリと共存できるようになりました。
- Java : コードレベルでの互換性はありません。class ファイルに、コンパイルバージョンが含まれており、下位のランタイムででは実行できません。ただし、上位のランタイムは、下位のクラスを読み込んで実行できます(非ジェネリックなライブラリを呼ぶことは可能
)。
- C++ :ネイティブコードに互換性は、、、、
補足すると、C++ の場合はある種のマクロとして展開、コンパイルされますので、template 指定に int やポインタ、関数ポインタであろうと指定することができます。
それはそれで可読性や保守性はどうだろう?という疑問はあるでしょうが、自由度は最大でしょう。
たまに、たらいまわし関数をコンパイル時に template で展開計算して実行時の計算コストを 0 にするとかいう神がかった荒業をする人もいます。