投稿数 - 437, コメント - 52891, トラックバック - 156

List<T>ForEach() と匿名メソッド

.NET2.0 からジェネリックが使えるようになり、C#2.0 では匿名メソッドが使えるようになったので、以下のようなコードが書ける。

List<string> list = new List<string>();
list.Add("aiueo");
list.Add("abcde");
list.ForEach(delegate(string text)
{
    Console.WriteLine(text);
});

こんなコードを見て、「意味ねぇぇ」と思うのは私だけだろうか。

List<T>.FindAll() 等だったら納得できる。でも、ForEach() は普通に foreach ステートメントで回せば済む事だ。

匿名メソッドを使わないで、普通のデリゲートならまだ納得できる。ループ部分のロジックの共用が出来るからだ。でも、匿名メソッドにはそれがない。

よって、List<T>.ForEach() と匿名メソッドの組み合わせに限っては「意味ねぇぇ」。

投稿日時 : 2006年5月23日 12:44

フィードバック

# re: List&lt;T&gt;ForEach() と匿名メソッド

>よって、List<T>.ForEach() と匿名メソッドの組み合わせに限っては「意味ねぇぇ」。

個人的にはこの辺りの違いが面白かったりするんですが……
http://msmvps.com/blogs/jon.skeet/archive/2006/01/20/foreachperf.aspx

とは言え、こういうのは「List<T>.ForEach()と匿名メソッドの方が foreach より速い」と憶えられるのも問題なので、紹介の仕方が難しいわけですが。
2006/05/23 13:27 | NyaRuRu

# re: List&lt;T&gt;ForEach() と匿名メソッド

お~性能の視点ですか。面白いですね。
2006/05/24 0:37 | 囚人

# re: List&lt;T&gt;ForEach() と匿名メソッド

匿名メソッドでなければめんどくさいことのうちに、変数の引き渡しがあります。
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
int i = 3;
list.ForEach(delegate(int value)
{
Console.WriteLine(value + i);
});

なんてことができるのです。
え?
foreachでできるって?

できるできないだけで語るのはあまり意味がないでしょう。
2006/05/24 12:57 | 中博俊

# re: List&lt;T&gt;ForEach() と匿名メソッド

こんな違いも:
List#ForEach は、途中で List に要素が追加・削除されようともエラーなく動きました。
2006/07/15 4:31 | 通りすがり

# re: List&lt;T&gt;ForEach() と匿名メソッド

>List#ForEach は、途中で List に要素が追加・削除されようともエラーなく動きました。

お~そうなんですか?
でも意図通りに動かないのでは?
2006/07/15 12:07 | 囚人

# re: List&lt;T&gt;ForEach() と匿名メソッド

ループの対象になるリストの要素が、最初の状態における要素に固定されるようです (追加・削除の処理はループの後に行われる?)。
ただ、 MSDN などに明記された仕様ではないので、イマイチ不安です。
2006/07/15 13:20 | 通りすがり

# re: List&lt;T&gt;ForEach() と匿名メソッド

ForEach() 内で追加してみたところ、無限に追加されてオーバーフローになりました。(C#2.0)
削除も、今ループしている要素が削除されてしまい、意図通りに動かないようです(削除したい箇所が削除できない?)。^^;

どういう環境で実験なされましたでしょうか?
2006/07/15 16:59 | 囚人

# re: List&lt;T&gt;ForEach() と匿名メソッド

申し訳ない、手元のソースを消してしまい、再現できるものがもう残っておりません。。

簡単に書くと、以下のような感じです。

class Hoge
{
public void Execute();
internal protected void OnAdded();
public event EventHandler Added;
}

class HogeController
{
List<Hoge> TempHoges;
List<Hoge> Hoges;

public void Execute()
{
while(0 < TempHoges.Count)
{
TempHoges.ForEach(delegate(Hoge hoge)
{
this.Hoges.Add(hoge);
hoge.OnAdded();
});
}
// Hoge 群実行の処理。略
}

public void Add(Hoge hoge)
{
this.TempHoges.Add(hoge);
}

// 略
}

HogeController は Hoge のインスタンス群を管理します。
HogeController#Execute で、保持している Hoge 群を実行 (Hoge#Execute) します。
HogeController#Add は Hoge のインスタンスをコントローラに追加しますが、追加直後は一時領域 (TempHoges) に保存された状態であり、次回の実行時に改めて追加されます。

ある Hoge#Added イベントに HogeController#Add を実行するようなデリゲードを追加しました。 TempHoges リストに影響がでるはずなので、エラーが出るのかなと思いきや出ませんでした。
2006/07/15 17:58 | 通りすがり

# re: List&lt;T&gt;ForEach() と匿名メソッド

P.S.
結局、 ForEach を使わず、リストを一旦 ToArray() して foreach 文を使うことにより、エラーが起こりえるのを回避しました。
2006/07/15 18:03 | 通りすがり

# re: List&lt;T&gt;ForEach() と匿名メソッド

>ある Hoge#Added イベントに HogeController#Add を実行するようなデリゲードを追加しました。

この部分の実装が書かれていないので何とも言えませんが、TempHoges.ForEach() 内に TempHoges を操作するようなコードが見当たらないようです。

どんなコードでしょうか。
2006/07/16 3:05 | 囚人

# re: List&lt;T&gt;ForEach() と匿名メソッド

Hoge のインスタンス hoge と HogeController のインスタンス hogeController があったとして、

hoge.Added += delegate
{
hogeController.Add(new Hoge());
};

さらに、 hoge がすでに hogeController に加わっているとすると、

hogeController.Execute();

を実行したときにこのデリゲードが呼ばれます。

あと、 Hoge クラスの OnAdded メソッドをはしょって書いてしまいましたが、こんな感じです。
internal protected override OnAdded()
{
if(this.Added != null)
this.Added(this, null); // 引数は適当
}
2006/07/16 16:04 | 通りすがり

# re: List&lt;T&gt;ForEach() と匿名メソッド

かなり入り組んでますねぇ^^;
ちょと時間を置いて検証してみまっす!
2006/07/17 23:55 | 囚人

コメントの投稿

タイトル
名前
URL
コメント