最近、Genericを利用したクラスを作成する機会があった。
もともと、以下のような感じのGenericを利用していないクラスがあったのをGenericに対応した。
public abstract class ほにゃAbstract
{
public ほにゃAbstract()
{
}
public abstract DataTable TableData
{get;}
}
public class ふが :ほにゃabstract
{
private 型のついたテーブル型 _data = new 型のついたテーブル型();
public override DataTable TableData
{
get
{
return _data;
}
}
}
というクラスがあったとして、Dataプロパティを利用するときは、常にDataTable型なので、型付DataSetで定義したテーブルを返す時は
ふが ふがインスタンス = インスタンス作成();
型のついたテーブル型 データ = (型のついたテーブル型)ふがインスタンス.TableData;
といった感じにいちいちキャストする必要があったが
public abstract class ほにゃAbstract<T> where T:DataTable,new()
{
public abstract ほにゃAbstract()
{
}
private T _data = new T();
public abstract T TableData
{
get
{
return _data;
}
}
}
public class ふが :ほにゃabstract<型のついたテーブル型>
{
}
とすることで、
ふが ふがインスタンス = インスタンス作成();
型のついたテーブル型 データ = ふがインスタンス.TableData;
とキャストしなくて良くなった。
ここで、重要だと思ったのが、
public abstract class ほにゃAbstract<T> where T:DataTable,new()
のwhere以降の部分で、Tに設定できる型の条件を指定できる。
T:DataTable
で、DataTableを基本型に持つクラスのみ指定可能なので、DataTableを継承した型である事という条件がクリアできる。
次に
new()
とつけることで、
private T _data = new T();
といったように抽象クラス側でインスタンスの生成ができるようになったので、いちいちサブクラス側でメンバを設定する必要が無くなった。
今更だし、凄い簡単な話なんだけど、便利だと思った。
そういえば、MSDNライブラリの型パラメータの制約ページの構文を説明している箇所で
http://msdn.microsoft.com/ja-jp/library/d5x73970.aspx
where T:struct
where T:class
のままで良いのに、
where T:構造体
where T:クラス
になっていた。
翻訳されすぎ。