일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 추상 프로퍼티
- this 키워드
- 프로퍼티
- 이것이C#이다
- 컬렉션 초기화
- 인터페이스의 프로퍼티
- 클래스
- c#
- 가변배열
- base()
- 중첩클래스
- System.Array
- 접근 한정자
- 프로퍼티와 생성자
- 배열초기화
- 인터페이스 상속
- 오버라이딩
- 배열
- 무명형식
- as
- is
- 분할 클래스
- 인터페이스 예제
- 클래스 연습문제
- 일반화 클래스
- 자동구현프로퍼티
- 형식변환
- 인덱서
- 메소드숨기기
- 튜플
- Today
- Total
제로의영역
10.10 foreach가 가능한 객체 만들기 본문
* 본 블로그 글은 머리가 아~~~주 나쁜 왕X100초보가 프로그래밍을 공부하면서 정리를 위해 작성하는 글입니다. 잘못 정리되거나 제가 잘못 이해한 글은 이해 및 조언 부탁드립니다.
* 공부는 '이것이 C#이다' 책을 보고 하고 있습니다. 참고로 저같은 왕초보가 보기 어렵게 써져 있어서 별도의 정리 문서를 만들게 되었습니다.
1. foreach가 가능한 객체를 만들 필요성
(1) 요소의 위치를 위한 인덱스 변수를 선언할 필요가 없음
(2) 세미콜론을 2개나 넣지 않아도 됨
(3) 조건문이나 증감식을 쓰지 않아도 됨
(4) 쓰기에도 좋고, 읽기에도 좋음
2. foreach문 사용 조건
(1) 배열이나 리스트 같은 컬렉션에서만 사용 가능
(2) MyList는 foreach문이 가능하지 않음 - foreach 문이 객체 내의 요소를 순회하기 위해서는 foreach 문과의 약속을 지켜야 하는데, MyList는 그 약속이 뭔지도 모름
(3) foreach 구문은 IEnumerable과 IEnumerator를 상속하는 형식만 지원 - MyList 클래스도 IEnumerable과 IEnumerator를 상속하기만 하면 foreach 문을 이용해서 요소를 순회할 수 있게 할 수 있음
3. 사용 방법
(1) IEnumerable 인터페이스가 갖고 있는 메소드는 'IEnumerator GetEnumerator( )' 하나로 MyList는 이 메소드를 구현해야 함.
(2) GetEnumerator( ) 메소드를 구현할 때는 yield return 문의 도움을 받아야 함.
(3) yield retrutn문은 현재 메소드(GetEnumerator( ))의 실행을 일시 정지시켜 놓고 호출자에게 결과를 반환.
(4) 메소드가 다시 호출되면, 일시 정지된 실행을 복구하여 yield return 또는 yield break 문을 만날 때까지 나머지 작업을 실행
예제1)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace _10._10._1
{
class MyEnumerator
{
int[] numbers = { 1, 2, 3, 4 };
public IEnumerator GetEnumerator()
{
yield return numbers[0];
yield return numbers[1];
yield return numbers[2];
yield break; //yield break는 GetEnumerator()메소드를 종료시키기 때문에 아래 코드는 실행되지 않음.
yield return numbers[3];
}
}
class Program
{
static void Main(string[] args)
{
var obj = new MyEnumerator();
foreach (int i in obj)
Console.WriteLine(i);
}
}
}
실행 결과:
1
2
3
4. IEnumerator 인터페이스
(1) GetEnumerator( ) 메소드는 IEnumerator 인터페이스를 상속하는 클래스의 객체를 반환
(2) IEnumerator 인터페이스의 메소드및 프로퍼티 목록
메소드 또는 프로퍼티 | 설명 |
boolean MoveNext( ) | 다음 요소로 이동. 컬렉션의 끝을 지난 경우에는 false, 이동이 성공한 경우에는 true를 반환 |
void Reset( ) | 컬렉션의 첫 번째 위치의 "앞"으로 이동. 첫 번째 위치가 0번이라면, Reset( ) 을 호출하면-1번으로 이동. 첫 번째 위치로의 이동은 MoveNext( )를 호출한 다음에 이루어짐. |
Object Current{get;} | 컬렉션의 현재 요소를 반환 |
예제2)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace _10._10._2
{
class MyList : IEnumerable, IEnumerator
{
private int[] array;
int position = -1; //컬렉션의 현지 위치를 다루는 변수. 초기값이 0이 아닌 -1임. 0은 배열의 첫 번째 요소를 가리키는 수. position이 이 값(0)을 갖고 있을 때 foreach문이 첫 번째 반복을 수행하면 MoveNext()메소드를 실행하고, 이 때 position이 1이 되어 두 번째 요소를 가져오는 문제 발생.
public MyList()
{
array = new int[3];
}
public int this[int index]
{
get
{
return array[index];
}
set
{
if(index >= array.Length)
{
Array.Resize<int>(ref array, index + 1);
Console.WriteLine($"Array Resized:{array.Length}");
}
array[index] = value;
}
}
// IEnumerator 멤버
public object Current //IEnumerator로부터 상속받은 Current프로퍼티는 현재 위치의 요소를 반환
{
get
{
return array[position];
}
}
//IEnumerator 멤버
public bool MoveNext() //IEnumerator로부터 상속받은 MoveNext()메소드. 다음 위치로의 요소로 이동
{
if(position==array.Length - 1)
{
Reset();
return false;
}
position++;
return (position < array.Length);
}
//IEnumerator멤버
public void Reset() //IEnumerator로부터 상속받은 Reset()메소드, 요소의 위치를 첫 요소의 "앞"으로 옮김
{
position = -1;
}
//IEnumerable 멤버
public IEnumerator GetEnumerator()
{
for(int i=0;i<array.Length;i++)
{
yield return (array[i]);
}
}
}
class Program
{
static void Main(string[] args)
{
MyList list = new MyList();
for (int i = 0; i < 5; i++)
list[i] = i;
foreach (int e in list)
Console.WriteLine(e);
}
}
}
실행결과
Array Resized:4
Array Resized:5
0
1
2
3
4
'C#' 카테고리의 다른 글
11.3 일반화 클래스 (0) | 2019.12.30 |
---|---|
11.1 일반화 프로그래밍 & 11.2 일반화 메소드 (0) | 2019.12.27 |
10.9 인덱서 (0) | 2019.11.18 |
10.8 컬렉션을 초기화하는 방법 (0) | 2019.09.19 |
10.6 가변 배열 (0) | 2019.08.09 |