C#再入門 〜その1.ジェネリックス
VisualStudio2010になりC#のバージョンも4.0になりました。度重なるバージョンアップによってC#は多機能になり、様々なプログラミングパラダイムを取り入れ、成長してきました。
C#の機能をもう一度見直そうということで、機能ごとにピックアップして説明していこうかと思います。
C#1.0の頃
C#1.0のころ、可変長配列やハッシュテーブルを使う場合、要素はobject型として扱わなければならず、要素を取り出す際にキャストの必要性がありました。また、想定外の型のオブジェクトを追加してもコンパイルエラーは出てくれません。
using System; using System.Collections; namespace GenericsSample{ class Program{ static void Main(string[] args){ ArrayList list = new ArrayList(); list.Add(1); list.Add(5); list.Add(8); int x = (int)list[1];//ここでキャスト list.Add("hello");//文字列を代入してもエラー出ない int y = (int)list[3];//ランタイムエラー } } }
キャストは手間がかかりますし、キャストが失敗する可能性も含め実装しなければなりません。
C#2.0の頃
それを解決するため、ジェネリックスという機能が追加されました。
using System; using System.Collections.Generic; namespace GenericsSample{ class Program{ static void Main(string[] args){ IList<int> list = new List<int>(); list.Add(1); list.Add(5); list.Add(8); int x = list[1];//キャストの必要性なし list.Add("hello");//ここでコンパイルエラー } } }
IList
ジェネリッククラスを使うことにより、コンパイラによる要素の型チェックが行われるようになり、間違った型のオブジェクトを代入しようとした場合コンパイルエラーになります。
コンパイラさんがきちんとチェックしてくれるので、キャストによる実行時エラーに怯える心配もなくなります。
List
ジェネリッククラスの作成
ジェネリッククラスや、ジェネリックメソッドは使うだけでなく自分で定義することもできます。例としてスタッククラスを作ってみました。
class Stack<T>{ private LinkedList<T> source; public Stack(){ source = new LinkedList<T>(); } public void Push(T item){ source.AddLast(item); } public T Pop(){ var result = source.Last; source.RemoveLast(); return result.Value; } }
Tというのが型パラメータです。使い方はIList
例えばStack
static void Main(string[] args){ Stack<string> strs = new Stack<string>();//stringのスタック strs.Push("abc"); strs.Push("hello"); strs.Push("foo"); Console.WriteLine(strs.Pop()); // foo Stack<int> nums = new Stack<int>();//intのスタック nums.Push(3); nums.Push(4); nums.Push(5); Console.WriteLine(nums.Pop());// 5 }
また、型パラメータにはwhereで厳密な制約を出来たり、C#4.0から共変、反変を指定できるようになり、使いこなせば非常に心強い機能です。
次はコレクションクラスの説明を行いたいと思います。