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 : <インターフェース名> |
この型引数は、指定されたインターフェイスであるか、 そのインターフェイスを実装している必要があります。 複数のインターフェイス制約を指定することができます。 制約のインターフェイスを汎用的にすることもできます。 |

コメント
コメントを投稿