ジェネリック
ジェネリックを使うことで、メソッドを任意の型に対応させることができる。
using System;
namespace Sample
{
class Program
{
static T Max<T>(T a, T b) where T : IComparable
{
return a.CompareTo(b) > 0 ? a : b;
}
static void Main(string[] args)
{
Console.WriteLine(Max(1, 2));
Console.WriteLine(Max(3.1, 2.2));
}
}
}
上記コードで、Tの部分には任意の型が入る。Max(1,2)ならint、Max(1.1, 2.1)ならdoubleで演算が行われる。whereで、Tの型にIComparebleを実装しているという制約を加えている。また、ジェネリックを使うと演算子を利用できなくなるため、比較にはIComparebleで実装が保証されているCompareメソッドを使用している。
ジェネリックなクラスは以下のように定義し、利用する。
using System;
namespace Sample
{
class Stack<T>
{
T[] buf;
int top;
public Stack(int max) { this.buf = new T[max]; }
public void Push(T val) { this.buf[this.top++] = val; }
public T Pop() { return this.buf[--this.top]; }
public int Size { get { return this.top; } }
public int MaxSize { get { return this.buf.Length; } }
}
class Program
{
static void Main(string[] args)
{
var iStack = new Stack<int>(4);
var dStack = new Stack<double>(5);
for (int i = 1; i <= iStack.MaxSize; ++i)
{
iStack.Push(i);
}
while (iStack.Size > 0)
{
Console.WriteLine("{0}", iStack.Pop());
}
}
}
}
defaultキーワード
default(Type)はTypeが数値型の場合は0、参照型の場合はnullを返す。
using System;
namespace Sample
{
class Program
{
static void FillWithDefault<T>(T[] array)
{
for (int i = 0, len = array.Length; i < len; ++i)
{
array[i] = default(T);
}
}
static void Main(string[] args)
{
int[] array = new int[5];
FillWithDefault(array);
foreach (int n in array)
{
Console.WriteLine(n);
}
}
}
}
共変性と反変性
C#4.0以上では、ジェネリックの型のパラメータに共変性・反変性を持たせることができる。
正直言って、この本だけだと共変性と反変性はよく理解できなかった。MSDNのジェネリックの共変性と反変性の方が、コード例が豊富でわかりやすい。
共変性は指定された型と、その派生元の型を使用できること。反変性は、指定された型と、その派生型を使用できること。指定された型のみが使用できる場合は不変性という。
using System;
using System.Collections.Generic;
namespace Sample
{
class Base { }
class Derived : Base { }
class Program
{
static void Main(string[] args)
{
// IEnumerable<out T> と定義されているので、Derivedの派生元のBaseも使える
IEnumerable<Derived> ed = new List<Derived>();
IEnumerable<Base> eb = ed;
// Action<in T> と定義されているので、Baseの派生型のDerivedも使える
Action<Base> ab = (target) => { Console.WriteLine(target.GetType().Name); };
Action<Derived> ad = ab;
ad(new Derived());
}
}
}
正直言って、まだちゃんと理解できているとはいいがたい。もう少し実例を通して学んでいきたい。