イテレーターの仕組み
イテレーター(反復)動作についてC#では、仕組みが用意されています。
ユーザーは、簡易に使えるように内部で処理をされていますが、今回は、どのようにコードがコンパイラで展開されているのかをみてみましょう
目次
yield returnを2行のみ
ユーザー作成コード
using System;
using System.Collections.Generic;
namespace YieldTest
{
class Program
{
static void Main(string[] args)
{
foreach (var item in Collection())
{
Console.WriteLine(item);
}
}
private static IEnumerable<object> Collection()
{
yield return 1;
yield return 2;
}
}
}
実行結果
1
2
コンパイラが展開したコード
複雑にはなっていますが、状態管理(ステート管理)を行い、今どのフェーズか(実行中?終了?)を都度管理しているのがわかります。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
namespace YieldTest
{
internal class Program
{
[CompilerGenerated]
private sealed class MyClass : IEnumerable<object>, IEnumerable, IEnumerator<object>, IDisposable, IEnumerator
{
private int state;
private object current;
private int initialThreadId;
object IEnumerator<object>.Current
{
get
{
return current;
}
}
object IEnumerator.Current
{
get
{
return current;
}
}
public MyClass(int state)
{
this.state = state;
initialThreadId = Environment.CurrentManagedThreadId;
}
void IDisposable.Dispose()
{
}
private bool MoveNext()
{
switch (state)
{
default:
return false;
case 0:
current = 1;
state = 1;
return true;
case 1:
current = 2;
state = 2;
return true;
case 2:
state = -1;
return false;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
if (state == -2 && initialThreadId == Environment.CurrentManagedThreadId)
{
state = 0;
return this;
}
return new MyClass(0);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<object>)this).GetEnumerator();
}
}
private static void Main(string[] args)
{
IEnumerator<object> enumerator = Collection().GetEnumerator();
try
{
while (enumerator.MoveNext())
{
object current = enumerator.Current;
Console.WriteLine(current);
}
}
finally
{
if (enumerator != null)
{
enumerator.Dispose();
}
}
}
private static IEnumerable<object> Collection()
{
return new MyClass(-2);
}
}
}
yield returnをfor文で繰り返す
ユーザー作成コード
using System;
using System.Collections.Generic;
namespace YieldTest
{
class Program
{
static void Main(string[] args)
{
foreach (var item in Collection())
{
Console.WriteLine(item);
}
}
private static IEnumerable<object> Collection()
{
for (int i = 0; i < 10; i++)
{
yield return i;
}
}
}
}
実行結果
0
1
2
3
4
5
6
7
8
9
コンパイラが展開したコード
複雑にはなっていますが、状態管理(ステート管理)を行い、今どのフェーズか(実行中?終了?)を都度管理しているのがわかります。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace YieldTest
{
internal class Program
{
private sealed class MyClass : IEnumerable<object>, IEnumerable, IEnumerator<object>, IDisposable, IEnumerator
{
private int state;
private object current;
private int initialThreadId;
private int next;
object IEnumerator<object>.Current
{
get
{
return current;
}
}
object IEnumerator.Current
{
get
{
return current;
}
}
public MyClass(int state)
{
this.state = state;
initialThreadId = Environment.CurrentManagedThreadId;
}
void IDisposable.Dispose()
{
}
private bool MoveNext()
{
int num = state;
if (num != 0)
{
if (num != 1)
{
return false;
}
state = -1;
next++;
}
else
{
state = -1;
next = 0;
}
if (next < 10)
{
current = next;
state = 1;
return true;
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
if (state == -2 && initialThreadId == Environment.CurrentManagedThreadId)
{
state = 0;
return this;
}
return new MyClass(0);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<object>)this).GetEnumerator();
}
}
private static void Main(string[] args)
{
IEnumerator<object> enumerator = Collection().GetEnumerator();
try
{
while (enumerator.MoveNext())
{
object current = enumerator.Current;
Console.WriteLine(current);
}
}
finally
{
if (enumerator != null)
{
enumerator.Dispose();
}
}
}
private static IEnumerable<object> Collection()
{
return new MyClass(-2);
}
}
}
ディスカッション
コメント一覧
まだ、コメントがありません