본문 바로가기
C#

[C#] 인덱서(Indexer)와 반복기(iterator, yield 키워드), 지연된 연산

by RucA 2024. 4. 30.
728x90
반응형

클래스의 인스턴스를 인덱싱해주는 인덱서와 점진적으로 반복하도록 해주는 반복기(이터레이터)와 yield 키워드의 사용법을 정리하고, 지연된 연산이라는 개념을 소개한다.

 

 

인덱서 (Indexer)


인덱서는 클래스의 인스턴스를 배열처럼 인덱싱해주는 구문으로, 매개 변수를 사용하는 점을 제외하면 속성을 유사한 형태이다. 배열을 쓰듯 인덱스로 속성을 초기화 및 값을 가져올 수 있다.

 

  • 정수형 인덱서 : 정수형 매개변수를 받는 인덱서
    • this[ int index ]
using System;

class IndexerPractice
{
    private string name;
    
    //정수형 인덱서 : this[int index]
    public string this[int index]
    {
        get { return name; }
        set { name = value; }
    }
    
    static void Main()
    {
        var indexer = new IndexerPractice();
        
        //인덱서를 활용
        indexer[0] = "Index1";
        Console.WriteLine(indexer[0]);
        
        indexer[1] = "Index2";
        Console.WriteLine(indexer[1]);
    }
}
//출력 : Index1 Index2

 

위의 예제는 직관성을 위해 name 변수 하나에 접근했지만, 인덱서는 그 이름에 맞게 배열류의 필드와 궁합이 좋다.

 

  • 정수형 인덱서 - 배열 형식의 필드 사용 
using System;

class IndexerPractice
{
    private string[] _names;
    
    public IndexerPractice(int count = 5)
    {
        _names = new string[count];
    }
    
    public string this[int index]
    {
        get { return _names[index]; }
        set { _names[index] = value; }
    }
    
    static void Main()
    {
        var indexer = new IndexerPractice(3);
        
        indexer[0] = "Index0";
        indexer[1] = "Index1";
        indexer[2] = "Index2";
        
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine(indexer[i]);
        }
    }
}
//출력 : Index0 Index1 Index2

 

  • 문자열 인덱서 : 문자열 매개변수를 받는 인덱서
using System.Collections;

class IndexerPractice
{
    private Hashtable _names = new Hashtable();
    
    public string this[string key]
    {
        get { return _names[key].ToString(); }
        set { _names[key] = value; }
    }
    
    static void Main()
    {
        var indexer = new IndexerPractice();

        indexer["Kim"] = "Bob";
        indexer["Hello"] = "World";

        Console.WriteLine($"Kim : {indexer["Kim"]}");
        Console.WriteLine($"Hello : {indexer["Hello"]}");
    }
}

 

위는 컬렉션의 해시테이블과 연계해서 문자열 인덱서를 사용하는 예제이다.

 

 

반복기 (iterator) : yield 키워드


반복기는 영어 그대로 이터레이터라고 읽기도 한다. 반복기는 배열과 컬렉션 등의 데이터를 단계적으로 반복할 때 사용할 수 있다. 반복기를 구현할 때는 IEnumerable 또는 IEnumerable<T> 인터페이스와 yield 키워드를 사용해 구현한다.

 

  • 반복기 구현 : IEnumerable
using System;
using System.Collections;

class YieldPractice
{
    //반복기 구현 : yield 키워드와 IEnumerable 인터페이스 사용
    static IEnumerable yield1()
    {
        yield return "Yield 1";
        yield return "Yield 2";
        yield return "Yield 3";
    }

    //for문을 활용할 수 있다
    static IEnumerable yield2()
    {
        for (int i = 1; i <= 5; i++)
        {
            yield return i;
        }
    }
    
    static void Main()
    {
        foreach (var v in yield1())
        {
            Console.Write($"{v} \t");
        }
        Console.WriteLine();

        foreach (var v in yield2())
        {
            Console.Write($"{v} \t");
        }
        Console.WriteLine();
    }
}

 

  • 반복기 구현 : IEnumerable<T> 
    • 메서드 MoveNext() : 다음 단계로 넘어가며, 넘어갔다면 true를 반환
    • 속성 Current : 현재 가리키고 있는 반환값을 반환
using System;
using System.Collections.Generic;

class YieldPractice
{
    static IEnumerable<int> Pass(int[] scores, int cutLine)
    {
        foreach (var score in scores)
        {
            if (score >= cutLine)
            {
                yield return score;
            }
        }
    }
    
    static void Main()
    {
        int[] scores = { 55, 75, 60, 95, 100 };

        foreach (var score in Pass(scores, 80))
        { 
            Console.WriteLine(score);
        }
    }
}

 

위의 예제는 foreach로 자동적으로 다음 인자로 넘어가 메서드와 속성을 다루지는 않았지만, 만약 while문 등을 통해 독자적인 제어를 구현하고자 한다면 사용하면 좋을 듯 하다.

 

 

지연된 연산 (Lazy Evaluation)


즉시 연산하는 것과 달리, 해당 코드가 필요할 때만 실행하는 것을 의미한다. 위의 반복기에서 yield문이 여러개 있을 경우, 전부 다 실행하는 것이 아니라 하나씩 내려오며 자신이 실행될 타이밍에만 실행되는데, 이는 지연된 연산이기에 가능하다.

728x90
반응형