Microsoft MVP성태의 닷넷 이야기
.NET Framework: 829. C# - yield 문을 사용할 수 있는 메서드의 조건 [링크 복사], [링크+제목 복사],
조회: 22914
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

C# - yield 문을 사용할 수 있는 메서드의 조건

다음과 같은 질문이 있군요. ^^

yield return의 리턴 타입 질문드립니다. 
; https://www.sysnet.pe.kr/3/0/5156

우선, yield 문을 사용할 수 있는 메서드 조건은 문서에 잘 나와 있습니다.

yield (C# Reference)
; https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/yield

  • 반환 타입은 반드시 IEnumerable, IEnumerable<T>, IEnumerator, IEnumerator<T> 중의 하나여야 한다.
  • 메서드의 인자에는 in, ref, out 조건을 가질 수 없다.

첫 번째 조건에 의해, C# 컴파일러는 yield 문이 사용된 메서드의 반환 형식이 IEnumerable이면 자동 생성되는 클래스를 IEnumerable과 IEnumerator를 함께 상속받도록 만듭니다. 반면 IEnumerator를 반환하는 메서드의 경우 IEnumerable은 필요 없으니 제외하고 IEnumerator만 구현합니다.

직접 확인해 볼까요? ^^ 본문(yield return의 리턴 타입 질문드립니다.)에 실린 예제를 보면,

using System;
using System.Collections;
using System.Collections.Generic;

public class NameSet : IEnumerable
{
    private List<string> names = new List<string>();

    public NameSet(params string[] values)
    {
        foreach (var e in values)
            this.names.Add(e);
    }

    public IEnumerable NameList()
    {
        int currentIndex = 0;

        while (currentIndex < names.Count)
        {
            yield return names[currentIndex];
            currentIndex++;
        }
    }

    public IEnumerator GetEnumerator()
    {
        int currentIndex = 0;

        while (currentIndex < names.Count)
        {
            yield return names[currentIndex];
            currentIndex++;
        }
    }
}

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var names = new NameSet("abc", "def", "ghi");

            foreach (var e in names.NameList())
                Console.WriteLine(e);

            foreach (var e in names)
                Console.WriteLine(e);
        }
    }
}

NameList 메서드의 경우 IEnumerable을 반환하므로 C# 컴파일러는 다음과 같은 식의 클래스를 생성해 줍니다.

[CompilerGenerated]
private sealed class <NameList>d__2 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IDisposable, IEnumerator
{
    // Fields
    private int <>1__state;
    private object <>2__current;
    public NameSet <>4__this;
    private int <>l__initialThreadId;
    private int <currentIndex>5__1;

    // Methods
    [DebuggerHidden]
    public <NameList>d__2(int <>1__state);
    private bool MoveNext();
    [DebuggerHidden]
    IEnumerator<object> IEnumerable<object>.GetEnumerator();
    [DebuggerHidden]
    IEnumerator IEnumerable.GetEnumerator();
    [DebuggerHidden]
    void IEnumerator.Reset();
    [DebuggerHidden]
    void IDisposable.Dispose();

    // Properties
    object IEnumerator<object>.Current { [DebuggerHidden] get; }
    object IEnumerator.Current { [DebuggerHidden] get; }
}

달리 말하면, NameList 메서드는 IEnumerable + IEnumerator가 구현된 클래스로 바뀌는 것입니다. 반면 IEnumerator를 반환하는 GetEnumerator 메서드는,

[CompilerGenerated]
private sealed class <GetEnumerator>d__3 : IEnumerator<object>, IDisposable, IEnumerator
{
    // Fields
    private int <>1__state;
    private object <>2__current;
    public NameSet <>4__this;
    private int <currentIndex>5__1;

    // Methods
    [DebuggerHidden]
    public <GetEnumerator>d__3(int <>1__state);
    private bool MoveNext();
    [DebuggerHidden]
    void IEnumerator.Reset();
    [DebuggerHidden]
    void IDisposable.Dispose();

    // Properties
    object IEnumerator<object>.Current { [DebuggerHidden] get; }
    object IEnumerator.Current { [DebuggerHidden] get; }
}

간단하게 IEnumerator만을 구현한 클래스로 바뀌는 것을 볼 수 있습니다.




참고로, foreach 구문은 IEnumerator/IEnumerable 인터페이스를 구현하지 않아도 되므로,

47. foreach 문을 사용하려면 IEnumerator/IEnumerable 인터페이스를 반드시 구현해야 할까?
; https://www.sysnet.pe.kr/2/0/11876#tag47

NameSet의 IEnumerable 상속은 (foreach에서만 사용한다면) 제거해도 무방합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 3/9/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 91  [92]  93  94  95  96  97  98  99  100  101  102  103  104  105  ...
NoWriterDateCnt.TitleFile(s)
11666정성태8/22/201819247사물인터넷: 37. 아두이노 - 코딩으로 대신하는 오실레이터 회로의 소리 출력파일 다운로드1
11665정성태8/22/201822810사물인터넷: 36. 오실레이터 회로 동작을 아두이노의 코딩으로 구현하는 방법파일 다운로드1
11664정성태8/22/201822264개발 환경 구성: 393. 윈도우 환경에서 elasticsearch의 한글 형태소 분석기 설치 [1]
11663정성태8/22/201825070개발 환경 구성: 392. 윈도우 환경에서 curl.exe를 이용한 elasticsearch 6.x 기본 사용법
11662정성태8/21/201817886사물인터넷: 35. 병렬 회로에서의 커패시터파일 다운로드1
11661정성태8/21/201820536사물인터넷: 34. 트랜지스터 동작 - 컬렉터-이미터 간의 저항 측정파일 다운로드1
11660정성태8/19/201820009사물인터넷: 33. 세라믹 커패시터의 동작 방식파일 다운로드1
11659정성태8/19/201819937사물인터넷: 32. 9V 전압에서 테스트하는 PN2222A 트랜지스터파일 다운로드1
11658정성태8/18/201823426사물인터넷: 31. 커패시터와 RC 회로파일 다운로드3
11657정성태8/18/201821553사물인터넷: 30. 릴레이(Relay) 제어파일 다운로드3
11656정성태8/16/201816575사물인터넷: 29. 트랜지스터와 병렬로 연결한 LED파일 다운로드1
11655정성태8/16/201819223사물인터넷: 28. 저항과 병렬로 연결한 LED파일 다운로드1
11654정성태8/15/201820503사물인터넷: 27. 병렬 회로의 저항, 전압 및 전류파일 다운로드1
11653정성태8/14/201821028사물인터넷: 26. 입력 전압에 따른 LED의 전압/저항 변화 [1]파일 다운로드1
11652정성태8/14/201818429사물인터넷: 25. 컬렉터 9V, 베이스에 5V와 3.3V 전압으로 테스트하는 C1815 트랜지스터파일 다운로드1
11651정성태8/14/201824174사물인터넷: 24. 9V 전압에서 테스트하는 C1815 트랜지스터 [1]파일 다운로드3
11650정성태8/14/201818337사물인터넷: 23. 가변저항으로 분압파일 다운로드1
11649정성태8/12/201820236사물인터넷: 22. 저항에 따른 전류 테스트파일 다운로드1
11648정성태8/12/201821553사물인터넷: 21. 퓨즈를 이용한 회로 보호파일 다운로드3
11647정성태8/8/201822406오류 유형: 476. 음수의 음수는 여전히 음수가 되는 수(절대값이 음수인 수)
11646정성태8/8/201817702오류 유형: 475. gacutil.exe 실행 시 "Failure initializing gacutil" 오류 발생
11645정성태8/8/201820326오류 유형: 474. 닷넷 COM+ - Failed to load the runtime. [1]
11644정성태8/6/201823405디버깅 기술: 118. windbg - 닷넷 개발자를 위한 MEX Debugging Extension 소개
11643정성태8/6/201823144사물인터넷: 20. 아두이노 레오나르도 R3 호환 보드의 3.3v 핀의 LED 전압/전류 테스트 [1]파일 다운로드1
11642정성태8/3/201821454Graphics: 20. Unity - LightMode의 ForwardBase에 따른 _WorldSpaceLightPos0 값 변화
11641정성태8/3/201826892Graphics: 19. Unity로 실습하는 Shader (10) - 빌보드 구현 [1]파일 다운로드1
... 91  [92]  93  94  95  96  97  98  99  100  101  102  103  104  105  ...