반응형
1. IEnumerable과 IEnumerator
[C#] IEnumerable, IEnumerator 그리고 yield
enumerate 영어로 수를 세다. 카운팅 하다! 두 인터페이스는 열거자와 관련이 있다.(반복자와 동일한…것 같다. 아닐수도..) using System.Collections; C#의 모든 Collections 컬렉션은 IEnumerable, IEnumerator를 상
ansohxxn.github.io
foreach를 사용할 수 있는 클래스를 만들기 위해서는,
IEnumerable 인터페이스와 IEnumerator 인터페이스를 상속하고 메소드와 프로퍼티를 구현해야 함
[C#] IEnumerator
IEnumerable 컬렉션namespace System.Collections{ public interface IEnumerable{ IEnumerator GetEnumerator(); } GetEnumerator()라는 하나의 메서드를 포함, foreach 구문 등에서 개체를 하나씩 넘겨주는 역할을 한다.이 메서드는
ongoing-yang.tistory.com
2. ForEach가 가능한 객체 만들기
// IEnumerable: 열거자를 리턴하는 Getter의 Getter
// IEnumerator: 데이터를 리턴(Getter)하는 열거자
class MyIntList : IEnumerable, IEnumerator
{
#region [MyIntList getter, setter, Length]
private int[] array;
int position = -1;
// 생성자: array를 길이가 3인 배열로 초기화
public MyIntList() { array = new int[3]; }
public int this[int index]
{
get { return array[index]; }
set { // array 길이보다 index가 클 경우 array를 리사이즈
if (index >= array.Length) {
Array.Resize<int>(ref array, index + 1);
Console.WriteLine($"Array Resized : {array.Length}");
}
array[index] = value;
}
}
#endregion
#region [IEnumerator 구현]
public IEnumerator GetEnumerator()
{
for (int i=0; i<array.Length; i++) {
yield return array[i];
}
}
// Current: 현재 위치의 데이터를 object 타입으로 리턴
public object Current
{
get { return array[position]; }
// T 객체인 array[position]을 리턴함
// 이건 IEnumerable 인터페이스를 구현한 프로퍼티가 아님
}
// MoveNext: 다음 위치로 이동하는데, 다음 위치에 데이터 있으면 true, 없으면 false 리턴
public bool MoveNext()
{
if (position == array.Length - 1) {
Reset();
return false;
}
position++;
return (position < array.Length);
}
// Reset: 인덱스를 초기 상태 위치로 이동시킴
public void Reset()
{
position = -1;
}
#endregion
}
class Program
{
static void Main(string[] args)
{
MyIntList int_list = new MyIntList();
int_list[0] = 0;
int_list[1] = 1;
int_list[2] = 2;
int_list[3] = 3;
int_list[4] = 4;
foreach (int no in int_list)
Console.WriteLine(no);
Console.ReadLine();
}
}
3. ForEach를 사용할 수 있는 일반화 클래스 만들기
// IEnumerable: 열거자 IEnumerator를 Get하는 데 필요한 인터페이스
public class MyClass<T> : ArrEnumerator<T>, IEnumerable<T>
{
public MyClass() : base() { }
public MyClass(int size) : base(size) { }
#region [IEnumerable<T> 구현]
// GetEnumerator: 컬렉션을 반복하는 열거자 IEnumerator를 반환
// IEnumerable<T>의 GetEnumerator
public IEnumerator<T> GetEnumerator() => this;
// GetEnumerator: 컬렉션을 반복하는 열거자 IEnumerator를 반환
// IEnumerable의 GetEnumerator
// IEnumerable을 상속받는 인터페이스 IEnumerable<T>
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
#endregion
}
// IEnumerator: 열거자를 구현하는 데 필요한 인터페이스
public class ArrEnumerator<T> : IEnumerator<T>
{
private T[] array;
int position = -1;
public ArrEnumerator() => array = new T[0];
public ArrEnumerator(int size) => array = new T[size];
public T this[int index]
{
get => array[index];
set { // array 길이보다 index가 클 경우 array를 리사이즈
if (index >= array.Length) {
Array.Resize(ref array, index + 1);
}
array[index] = value;
}
}
public int Length => array.Length;
public void Add(T item) => array[array.Length - 1] = item;
#region [IEnumerator<T> 구현]
// Current: 현재 위치의 데이터를 리턴
// IEnumerator<T>의 Current
public T Current => array[position];
// Current: 현재 위치의 데이터를 리턴
// IEnumerator의 Current
// IEnumerator를 상속받는 인터페이스 IEnumerator<T>
object IEnumerator.Current => Current;
// MoveNext: 다음 위치로 이동, 끝에 도달했는지 여부를 반환
// IEnumerator의 메소드 구현
public bool MoveNext()
{
// 위치가 길이를 벗어나는 경우
if (position == array.Length - 1) {
Reset();
return false;
}
position++;
return position < array.Length;
}
// Reset: 인덱스를 초기 상태 위치로
// IEnumerator의 메소드 구현
public void Reset() => position = -1;
// Dispose: 관리되지 않는 리소스 해제
// IDisposable의 메소드 구현
// IDisposable을 상속받는 인터페이스 IEnumerator<T>
public void Dispose() { }
#endregion
}
class Program
{
static void Main(string[] args)
{
MyClass<string> strList = new MyClass<string> {
[0] = "adc",
[1] = "def",
[2] = "ghi",
[3] = "jkl",
[4] = "mno"
};
foreach (string item in strList) {
Console.WriteLine(item);
}
Console.WriteLine();
while (strList.MoveNext()) {
Console.WriteLine(strList.Current);
}
Console.WriteLine();
MyClass<int> intList = new MyClass<int>(5) {
[0] = 0,
[1] = 1,
[2] = 2,
[3] = 3,
[4] = 4
};
foreach (int item in intList) {
Console.WriteLine(item);
}
Console.WriteLine();
while (intList.MoveNext()) {
Console.WriteLine(intList.Current);
}
Console.WriteLine();
Console.ReadLine();
}
}
반응형
'C# > 이것이 C#이다' 카테고리의 다른 글
13장. 대리자와 이벤트 (0) | 2023.05.18 |
---|---|
11장. 일반화 프로그래밍 (0) | 2023.05.18 |
9장. 프로퍼티 (0) | 2023.05.16 |
8장. 인터페이스와 추상 클래스 (0) | 2023.04.28 |
7장. 클래스: this 키워드, this() 생성자, 접근 한정자, static 변수, 구조체 (0) | 2023.04.19 |