컬렉션 안의 요소들을 하나씩 순차적으로 탐색하는 개체
C# 에서는 IEnuerator 인터페이스가 Enumerator 역할을 담당한다.
namespace System.Collections
{
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
}
| 멤버 | 설명 |
|---|---|
| object Current {get;} | 현재 가리키고 있는 요소를 반환 |
| bool MoveNext() | 다음 요소로 이동 이동 성공 시 true, 더 이상 없으면 false 반환 |
| void Reset() | 열거자를 처음 위치로 되돌림 (잘 사용하지 않는다고 함) |
public class MyCollectionEnumerator : IEnumerator
{
private int[] data;
private int position = -1;
public MyCollectionEnumerator(int[] data)
{
this.data = data;
}
public object Current
{
get
{
if (position == -1 || position >= data.Length)
{
throw new InvalidOperationException();
}
return data[position];
}
}
public bool MoveNext()
{
position++;
return (position < data.Length);
}
public void Reset()
{
position = -1;
}
}
컬렉션의 Enumerator 를 반환할 수 있는 기능을 가진 인터페이스.
namespace System.Collections
{
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
}
GetEnumerator() 메서드를 구현하여,
foreach 구문을 쓰면 컴파일러가 내부적으로 GetEnumerator() 를 호출해서
IEnumerator 를 받아온다.
이후 MoveNext() 와 Current 를 이용해 요소를 하나씩 꺼낸다.
public class MyCollection : IEnumerable
{
private int[] data;
public MyCollection(int[] data)
{
this.data = data;
}
public IEnumerator GetEnumerator()
{
return new MyCollectionEnumerator(this.data);
}
}
static void Main(string[] args)
{
int[] fibo = { 1, 1, 2, 3, 5, 8, 13, 21, 34 };
MyCollection myCollection = new MyCollection(fibo);
Console.WriteLine("myCollection with foreach");
foreach (var item in myCollection)
{
Console.Write($"{item} , ");
}
}
컬렉션의 내부 구조를 노출하지 않고, 그 안의 요소들을 순차적으로 접근할 수 있게 해주는 디자인 패턴.
using System.Collections;
namespace ConsoleApp3
{
internal class Program
{
public class Unit
{
public string Name { get; set; }
public Unit(string name)
{
Name = name;
}
}
public class UnitGroup : IEnumerable<Unit>
{
private List<Unit> units = new List<Unit>();
public void Add(Unit unit)
{
Console.WriteLine($"{unit.Name} 을 그룹에 추가");
units.Add(unit);
}
public IEnumerator GetEnumerator() => ((IEnumerable<Unit>)this).GetEnumerator();
IEnumerator<Unit> IEnumerable<Unit>.GetEnumerator()
{
for (int i = 0; i < units.Count; i++)
{
yield return units[i];
}
}
}
static void Main(string[] args)
{
Console.WriteLine("Enumerator\n");
UnitGroup unitGroup = new UnitGroup();
unitGroup.Add(new Unit("Goblin"));
unitGroup.Add(new Unit("Orc"));
unitGroup.Add(new Unit("Knight"));
unitGroup.Add(new Unit("Skeleton"));
Console.WriteLine("\nunitGroup with foreach\n");
foreach (Unit unit in unitGroup)
{
Console.Write($"{unit.Name}, ");
}
}
}
}
Unity 에서도 IEnumerator 를 쉽게 찾아볼 수 있다.
코루틴 실행 흐름을 제어하는 데 자주 사용된다.
StartCoroutine(FadeOut());
IEnumerator FadeOut()
{
Debug.Log("화면이 점차 어두워진다.");
yield return new WaitForSeconds(2f);
}
여기서 쓰이는 IEnumerator 는 위에서 쓰인 IEnumerator 와
같은 System.Collections.IEnumerator 네임스페이스를 공유한다.
다만 다른 점은
앞서 배운 Current 는 현재 요소를 반환하는 데 사용되고,
여기서는 yield return 뒤의 값을 Unity 엔진에 의해 해석된다는 점이다.
Ex) null : 다음 프레임까지 대기 후 계속 실행
Ex) WaitForSeconds(seconds) : 지정한 초 만큼 대기 후 계속 실행