C#にはジェネリックという仕組みがあります。
ジェネリックをざっくり説明すると、データ型が異なるだけの同じようなソースコードを1つで書けるようにする仕組みです。
具体的な例
ジェネリックが無い場合
例えば以下のような、2つの値を入れ替えるSwapという関数を作るとします。
public static void Swap(ref int a, ref int b) { int c; c = a; a = b; b = c; }
int型で定義された引数の値を入れ替えています。
ですが、使いたいデータ型はint型とは限らず、double型だったりfloat型だったりするかもしれません。その為double型用やfloat型用に同じような関数を何個も作らなければなりません。
ジェネリックを使った場合
ジェネリックを使えばそれらを1つのソースコードで済ませる事ができます。
public static void Swap<T>(ref T a, ref T b) { T c; c = a; a = b; b = c; }
メソッド名の後に<>を付けています。
<>で囲ったTという部分は、この「メソッドを使う時に指定しますよ」という意味になります。
使う時は以下のようになります。
Tはdouble型ですよと指定してSwapメソッドを呼び出しています。
double a = 1.0; double b = 2.0; Swap<double>(ref a, ref b);
ちなみに、引数のデータ型から型を推論してくれるので<double>の部分を省略する事もできます。
double a = 1.0; double b = 2.0; Swap(ref a, ref b);
ジェネリックなクラス
上の例では、メソッドに対して定義しました。
ジェネリックはクラスに対しても定義する事が出来ます。
public class Array<T> { private T[] m_Items; public void Set(int index, T item) { m_Items[index] = item; } public T Get(int index) { return m_Items[index]; } }
クラス名の後に<>を付けています。
クラス内のメンバ変数やメソッドの引数、戻り値などで利用できます。
ジェネリックはクラスやメソッドだけでなく、インターフェースやデリゲートにも使う事ができます。
複数の型を定義する
置き換えたい型の種類は1つだけとは限りません。
ジェネリックは複数の型を定義する事も可能です。
public class Pair<T1, T2> { public T1 m_Key; public T2 m_Value; }
型に対する制約を指定する
where句を指定する事で使用できる型に制約を設ける事が出来ます。
以下の例では、IComparableインターフェースを実装するクラスだけがTに指定できます。
public static T Max<T>(T a, T b) where T : IComparable<T> { if (0 < a.CompareTo(b)) return a; else return b; }
このように、IComparableのみに制約する事で、IComparableインターフェースのメソッドを呼び出す事が可能になります。
制約はインターフェース以外にも以下のようなものがあります。
where T : struct |
値の型である必要があります。 Nullable を除く任意の値の型を指定できます。 |
where T : class |
参照型である必要があります。 任意のクラス、インターフェイス、デリゲート、または配列型にも 適用されます。 |
where T : new() |
パラメーターなしのパブリック コンストラクターが必要です。 new() 制約を別の制約と併用する場合、 この制約を最後に指定する必要があります。 |
where T : <ベースクラス名> |
この型引数は、指定された基底クラスであるか、 そのクラスから派生している必要があります。 |
where T : <インターフェース名> |
この型引数は、指定されたインターフェイスであるか、 そのインターフェイスを実装している必要があります。 複数のインターフェイス制約を指定することができます。 制約のインターフェイスを汎用的にすることもできます。 |
関連記事
- C#の値型と参照型の違い
- C#のコンストラクタでオーバーロード
- C#のコンストラクタの継承
- C#のジェネリックを使おう
- C#のデリゲート (delegate) って何?
- C#のデリゲートお手軽にする匿名メソッド
- C#のラムダ式【=>】って何?
- C#で基底クラスのメソッドを置き換えるオーバーライド
- C#でキャストとas演算子を使いこなす
- C#で型を判別するtypeofとis演算子
- C#の値型でもnullを扱えるようにするNullable
- C#のリソース解放にはIDisposableとusingを使おう
- C#のStringとstring、Int32とint 違いは・・・ない!
- C#でasync/awaitを使った非同期処理
- C#で文字列を指定の区切り文字で分割
- C#のstring.Formatで桁数や書式を指定する
- C#の配列やListをソートする
- C#の配列やListを検索する (Find,FindAll,FindIndex)
- C#の配列やListを高速に検索する (BinarySearch)
- C#の配列の中に指定の要素が存在するかを調べる(LINQ Contains)
- C#の配列の中に条件を満たす要素が存在するかを調べる(LINQ Any)
- C#の配列から条件に合う要素を抽出する(LINQ Where)
- C#の配列で要素毎の処理結果を得る(LINQ Select)
- C#の配列を並び替える(LINQ OrderBy,ThenBy)
- C#の配列をグループ毎に処理する(LINQ GroupBy)
- C#の配列を内部結合(INNER JOIN)する(LINQ Join)
- C#の配列から最初の要素を取り出す(LINQ First,FirstOrDefault)
- C#の配列の重複要素を削除する(LINQ Distinct)
- C#でフォルダ内のファイル名一覧を取得する
- C#でテキストファイルを読み込む
- C#でテキストファイルに書き込む
- C#でバイナリファイルを読み込む
- C#でバイナリファイルに書き込む
コメントをお書きください