今さらながら .NET Framework 2.0 で搭載される Generics のことです。
といっても解説じゃありません(^^;
基本的には以下のような感じですね。
(以下に書いているコードは VS2005 CTP March 2004 では動きました)
private static void TestGenerics()
{
List<int> l = new List<int>();
l.Add(0);
l.Add(1);
l.Add(2);
l.Add(3);
// 普通に Count でループ
for (int i = 0; i < l.Count; ++i)
{
Console.WriteLine(l[i].ToString());
}
// もちろん foreach でもループできる
foreach (int n in l)
{
Console.WriteLine(n.ToString());
}
}
通常版では自動拡張する配列は ArrayList クラスでしたが、Generics 版は List
ただ、ArrayList はほんとに単なる 「自動拡張する配列」 でしたが、List
public sealed delegate bool Predicate
という Generic な delegate なんですね。
ついでに言うと、Find の戻り値は Nullable
で、Find を使ったコードはというと以下のような感じ。
private static void TestGenerics()
{
List<int> l = new List<int>();
l.Add(0);
l.Add(1);
l.Add(2);
l.Add(3);
// 0 か 2 のものを探して表示
Console.WriteLine(l.Find(IsZeroOrTwo).Value.ToString());
}
private static bool IsZeroOrTwo(int n)
{
return n == 0 || n == 2;
}
ここでは、static なメソッドである IsZeroOrTwo を delegate のコールバックメソッドとして使ってます。この場合 0 と 2 の 2つが見つかりますが、Find は最初に見つかったほうだけを返すので 0 だけが表示されます。
あぁ、そうそう、検索した結果見つからなくて null が返ってきたときのチェックを省略しちゃってますが、もちろん、ほんとはすべきです。
どうでしょ?すごくイイ!と思いませんか?(私は激しく思います。色を変えたくなるくらい)
ただ、C++ の STL を知らないと Predicate の考え方がわかりにくいかもしれませんね。
もう 1つ。List
それと ForEach っていうメソッドもあります。これの引数は 「Action
public sealed delegate void Action
です。Predicate との違いは戻り値が void なところだけですね。
この FindAll と ForEach を使うと、
private static void TestGenerics()
{
List<int> l = new List<int>();
l.Add(0);
l.Add(1);
l.Add(2);
l.Add(3);
// 0 か 2 のものを探して表示
l.FindAll(IsZeroOrTwo).ForEach(WriteLine);
}
private static bool IsZeroOrTwo(int n)
{
return n == 0 || n == 2;
}
private static void WriteLine(int n)
{
Console.WriteLine(n.ToString());
}
こんな感じに書けます。
さらに...
delegate は Anonymous Method として書けるはずです。ということは...
private static void TestGenerics()
{
List<int> l = new List<int>();
l.Add(0);
l.Add(1);
l.Add(2);
l.Add(3);
l.FindAll(delegate(int n)
{
return n == 1 || n == 3;
}).ForEach(delegate(int n)
{
Console.WriteLine(n.ToString());
});
}
っていう書き方ができるんです。
イイ!イイ!イイ!激しくイイ!
こりゃ楽しいや。
typedef 無いのがイタイなぁ。
返信削除テンプレートを使って作った方の名前を、何度も何度も書くのはいやん ;-p
ん? using でクラス名に別名つけられましたよね?
返信削除テンプレートで作った型にも別名つけられるのかな?
using IntList=List<int>;
みたく。。。
インライン(anonymous delegate)で書いてると、だんだんRubyに見えてきた。。。
返信削除predicateはLISP的。
さらにBeta1では T[]->IList<T> or T[]-> IEnumerable<T> Implicit Conversionがサポートされますので青柳さんのサンプルは
返信削除private static void TestGenerics()
{
List<int> l = new List<int>(new int[]{0,1,2,3});
l.FindAll(delegate(int n)
{
return n == 1 || n == 3;
}).ForEach(delegate(int n)
{
Console.WriteLine(n.ToString());
});
}
とかけるようになります。T[]->IList<T> Conversionについては近いうちに自分のBLOGで書こうと思っています。
>ん? using でクラス名に別名つけられましたよね?
返信削除>テンプレートで作った型にも別名つけられるのかな?
>using IntList=List<int>;
>みたく。。。
ソースファイルごとにusingしないとだめなんですか?