본문 바로가기

Software/C#.Net

[C#]Enumerable Type만들기 (IEnumerable과 IEnumerator)

먼저 다음코드를 보자
int[] myInt = {10,20,30,40};
foreach(int i in myInt)
{
   Console.WriteLine(i);
}
여기서 myInt즉, int 타입이 GetEnumerator()합수를 지원하기 때문에 foreach구문이 가능하다.
즉, foreach를 사용하려면, 무조건 GetEnumerator()를 지원해야 만 쓸 수 있다.
얘를 들어 다음과 같은 클래스가 있다면,
public class Car
{
private int currSpeed;
private string petName;
public int Speed
{
get { return currSpeed; }
set { currSpeed = value; }
}
public string PetName
{
get { return petName; }
set { petName = value; }
}
...
}
다음 class는 이를 저장하는 저장소 클래스
public class Garage
{
private Car[] carArray = new Car[4];
// Fill with some Car objects upon startup.
public Garage()
{
carArray[0] = new Car("Rusty", 30);
carArray[1] = new Car("Clunker", 55);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
}

그리고 이를 사용하는 Main
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
Garage carLot = new Garage();
// Hand over each car in the collection?
foreach (Car c in carLot)
{
Console.WriteLine("{0} is going {1} MPH",
c.PetName, c.Speed);
}
Console.ReadLine();
}
}
이를 compile하면 에러를 발생하고, Garage클래스가 GetEnumerator()를 구현하지 않았다고 알려준다. 이 함수는 IEnumerable에 의해 이루어지는 함수다. 이 interface는 System.Collections namespace에 있다. 어는 타입이든지 이를 지원하면, 그 타입의 내부를 열거할 수 있도록 외부로 노출 시키는 일을 하게 된다.
이 Interface는 다음과 같다.
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
GetEnumerator()함수는 다른 인터페이스 System.Collections.IEnumerator의 참조를 리턴한다.
이 인터페이스는 어느 타입이든지 container 내부를 열거할수 있도록 한다.
이 인터페이스는 호출클래스에게 다음과 같은 멤버를 가지도록 한다.(왜냐하면 이 Interface가 가진 가상함수가 이것이기 때문이다. )
public interface IEnumerator
{
bool MoveNext (); // 커서의 위치를 내부에서 한 위치 앞으로 가게한다.
object Current { get;} // 현재 아이템을 반환한다(read-only)
void Reset (); // 첫 멤버전으로 되돌린다. 첫멤버로 이동하는것이 아님!
}

그래서 이 기능을 제대로 사용하려면 상속을 받고 전함수를 다 구현해야 한다.
하지만 System.Array에는 이 모든 것을 이미 구현해놓았다. 그래서 그냥 System.Array에 대신요청하면 된다.
using System.Collections;
...
public class Garage : IEnumerable
{
// System.Array already implements IEnumerator!
private Car[] carArray = new Car[4];
public Garage()
{
carArray[0] = new Car("FeeFee", 200, 0);
carArray[1] = new Car("Clunker", 90, 0);
carArray[2] = new Car("Zippy", 30, 0);
carArray[3] = new Car("Fred", 30, 0);
}
public IEnumerator GetEnumerator()
{
// Return the array object's IEnumerator.
return carArray.GetEnumerator();
}
}
이렇게 함으로서 이제 쉽게 Garage타입에 foreach를 사용할 수 있을뿐더러, IEnumerator타입을 사용할 수도있다.
// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.Speed);