ページ

2005年10月27日木曜日

Anonymous Method はクロージャではない その2

Anonymous Method はクロージャではない」 のちょっとした続き。


NyaRuRu さんに
http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=7ab1ab2b-0821-416f-b2c6-da737f8005ea
を教えていただきました。


これは、「Anonymous Method が思ったように動かない。C# 仕様書の 20.8.10 を見ると動くはずでは?」 というような内容です。で、Microsoft からの回答は 「これは仕様書のバグ」 となってます。


http://msdn.microsoft.com/vcsharp/programming/language/ にある C# Language Specification 2.0, March 2005 Draft を見ると


foreach (ElementType element in collection) statement


は、


IEnumerator enumerator = ((IEnumerable)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
enumerator.Dispose();
}


となると書かれてます。確かにこれだと 「C#: Anonymous methods are not closures」 の正しく動く版のコードとほとんど同じように解釈されることになるので動かないとおかしいはずです。


http://www.ecma-international.org/publications/standards/Ecma-334.htm
こちらの ECMA-334 C# Language Specification 3rd edition (June 2005) だと 「15.8.4 The foreach statement」 が上記の Draft の 20.8.10 に対応すると思います。こちらには


foreach (V v in x) embedded-statement



{
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}


となると書かれています。なるほど、V の宣言がループの外になるのがほんとなんですね。だから動かなくて正解と。


で、仕様書を見て気づいたおまけ。
GetEnumerator() が返ってきたオブジェクトが IDisposable を実装している場合は finally で Dispose() を呼んでくれるんですね。確認してみたら 1.1 でもちゃんとそうなってます。

0 件のコメント:

コメントを投稿