지금 여기예요
� 909
남은 것들
#7. yield return으로 열거형 객체 생성하기
8장에서 우리는 IEnumerable 인터페이스를 배웠고, foreach문으로 어떻게 사용하는지 배웠습니다. C#과 .NET은 IEnumerable
인터페이스로 시작하는 여러분만의 컬렉션을 만드는 데 몇 가지 유용한 도구를 제공하고 있습니다. 이 Sport 열거형에서 순서대로
값을 반환하는 열거자를 만들어 봅시다.
enum Sport
{
Football, Baseball,
Basketball, Hockey,
Boxing, Rugby, Fencing,
}
직접 IEnumerable를 구현하고, Current 속성과 MoveNext() 메서드를 만들 수 있습니다.
class SportCollection : IEnumerable<Sport> {
public IEnumerator<Sport> GetEnumerator() {
return new ManualSportEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return GetEnumerator();
}
class ManualSportEnumerator : IEnumerator<Sport> {
int current = -1;
public Sport Current { get { return (Sport)current; } }
public void Dispose() { return; } // 처분할 게 없음
object System.Collections.IEnumerator.Current { get { return Current; } }
public bool MoveNext() {
int maxEnumValue = Enum.GetValues(typeof(Sport)).Length - 1;
if ((int)current >= maxEnumValue)
return false;
current++;
return true;
}
public void Reset() { current = 0; }
}
}
ManualSportCollection에 대해 루프를 도는 foreah문이 여기 있군요. 순서대로 스포츠 종목을 반환하고 있습니다(축구, 야구, 농
구, 하키, 복싱, 럭비 펜싱).
Console.WriteLine("SportCollection contents:");
SportCollection sportCollection = new SportCollection();
foreach (Sport sport in sportCollection)
Console.WriteLine(sport.ToString());
열거자를 만드는 데는 많은 작업이 필요합니다. 자기 자신의 상태를 관리해야 하고, 어떤 스포츠 종목이 반환되었는지도 파악해야
하죠. 다행히도, C#은 쉽게 열거자를 구현할 수 있도록 도와주는 유용한 도구를 제공하고 있습니다. 페이지를 넘겨 yield return에
대해서 자세히 알아보도록 하죠.
MoveNext() 메서드는 current 값을
증가시키고 이 열거형에서 다음 스포츠
종목을 반환하기 위해 이 값을 사용하고
있습니다.
이 열거자는 IEnumerator<Sport>를
구현하고 있군요. foreach문에서
Current 속성과 MoveNext() 메서드를
사용합니다.
IEnumerable은 GetEnumerator()라는 메서드
하나만 갖고 있습니다만, 우리는 또한 이 메서드를
반환하는 열거자를 위한 클래스도 만들어야 합니다.
15
장에서 배운 것을 떠올려 보면, 모든 컬렉션은 열거형이지만, 기술적인 관점에서 ICollection<T> 인터페이스를
구현하고 있지 않다면, 모든 열거형은 컬렉션이라고 말할 수는 없습니다. 이 책에서 컬력션을 만드는 방법을
여러분에게 알려 주지 않았지만, 열거자를 이해하는 것이 컬렉션을 만드는 데 충분한 도움이 되는 것은 확실합니다.
910 Appendix i
열거하기
yield return문은 자동으로 올-인-원(all-in-one) 열거자를 생성해 줍니다. 아래의 SportCollection 클래스는 이전 페이지와 똑같
지만, 열거자에 대한 코드가 달랑 세 줄만 있습니다.
class SportCollection : IEnumerable<Sport> {
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return GetEnumerator();
}
public IEnumerator<Sport> GetEnumerator() {
int maxEnumValue = Enum.GetValues(typeof(Sport)).Length;
for (int i = 0; i <= maxEnumValue; i++) {
yield return (Sport)i;
}
}
}
약간 이상하게 보이긴 하지만, 실제로 디버깅해 보면 무슨 일이 일어나는지 훤히 들여다 볼 수 있습니다. 컴파일러가 IEnumerator
혹은 IEnumerator<T>를 반환하는 yield return문을 사용하는 메서드를 만나면
자동으로 MoveNext()와 Current() 메서드가 추가
됩니다. 실행할 때, 첫 번째 yield return은 첫 번째 값을 foreach문에 반환합니다. foreach문이 계속 수행되면서(MoveNext() 메
서드를 호출함으로써), 컴파일러는 실행된 마지막 yield return
바로 다음
의 문장을 재개합니다. 열거자 메서드가 반환되면, Mov-
eNext() 메서드는 false를 반환합니다. 이 부분을 지면상으로 따라 하기 힘들 수 있지만, 디버거를 띄워 한 단계씩 코드 실행(F11)
을 한다면 훨씬 더 쉬울 겁니다. 조금 더 이해를 돕기 위해서, 4개의 이름을 반복해서 처리하는 NameEnumerator()라는 간단한
열거자가 나와 있습니다.
static IEnumerable<string> NameEnumerator() {
yield return "Bob"; // 이 문장 수행 후 이 메서드는 빠져나오고,
yield return "Harry"; // 다음 번에는 여기에서 다시 시작합니다.
yield return "Joe";
yield return "Frank";
}
그리고 여기에 반복처리를 하는 foreach문이 있습니다. 한 단계씩 코드 실행(F11)을 통해 무슨 일이 일어나는지 확인해 보세요.
IEnumerable<string> names = NameEnumerator(); // 이 곳에 중단점을 설정합니다
foreach (string name in names)
Console.WriteLine(name);
컬렉션에서 흔히 볼 수 있는 것이 또 하나 있는데, 바로
인덱서(indexer)
입니다. 리스트나 딕셔너리(myList[3] 혹은
myDictionary[“Steve”]와 같은)에서 객체를 추출하기 위해서 []를 사용할 때, 바로 인덱서를 사용합니다. 인덱서는 실제로 하나의
메서드입니다. 오직 한 개의 매개변수를 가진 점만 제외하고는 속성과 비슷해 보이죠.
IDE는 유용한 참조기능이 있습니다.
Indexer
를 입력한 뒤에 바로 탭 키를 두 번 누르면, IDE는 자동으로 인덱서의 스켈레톤을 추
가해 줍니다.
public Sport this[int index] {
get { return (Sport)index; }
}
인덱서에 3을 전달하면 enum 값인 Hockey를 반환합니다.
앞서 말했듯이, 이것은 SportCollection 클래스의
시작에 불과합니다. 아직 ICollection<Sport>
인터페이스가 구현이 안됐군요.
Get Head First C# (개정3판): 상상을 초월하는 객체지향 C# 학습법 now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.