문제

무엇보다도 "public ienumerator getEnumerator ()"메소드를 구현하는 인터페이스가 있으므로 Foreach 문에서 인터페이스를 사용할 수 있습니다.

나는 여러 클래스 에서이 인터페이스를 구현하고 그 중 하나에서는 빈 아이umerator를 반환하고 싶습니다. 지금 당장 나는 이것을 다음과 같이한다.

public IEnumerator GetEnumerator()
{
    ArrayList arr = new ArrayList();
    return arr.GetEnumerator();
}

그러나 나는 이것을 못생긴 해킹이라고 생각하고, 나는 도움이 될 수 없지만 빈 아이누머레이터를 반환하는 더 나은 방법이 있다고 생각합니다. 거기가 있습니까?

도움이 되었습니까?

해결책

C# 2에서 간단합니다.

public IEnumerator GetEnumerator()
{
    yield break;
}

당신은 필요합니다 yield break 컴파일러가 반복자 블록으로 취급하도록 강제 진술.

이것은 "사용자 정의"빈 반복기보다 효율적이지 않지만 더 간단한 코드입니다 ...

다른 팁

프레임 워크에는 추가 기능이 있습니다.

public static class Enumerable
{
    public static IEnumerable<TResult> Empty<TResult>();
}

이것을 사용하면 다음을 쓸 수 있습니다.

var emptyEnumerable = Enumerable.Empty<int>();
var emptyEnumerator = Enumerable.Empty<int>().GetEnumerator();

ienumerator를 구현하고 인스턴스를 반환하는 더미 클래스를 구현할 수 있습니다.

class DummyEnumerator : IEnumerator
{
    public object Current
    {
        get
        {
            throw new InvalidOperationException();
        }
    }

    public bool MoveNext()
    {
        return false;
    }

    public void Reset()
    {
    }
}

나는 호기심이 많았고 조금 더 갔다. 방법이 얼마나 효율적인지 확인하는 테스트를했습니다. yield break, Enumerable.Emtpy 그리고 커스텀 클래스.

dotnetFiddle에서 확인할 수 있습니다 https://dotnetfiddle.net/vtkmcq 또는 아래 코드를 사용하십시오.

190 000 반복을 사용하여 많은 DotnetFiddle 실행 중 하나의 결과는 다음과 같습니다.

수율 중단 : 00 : 00 : 00.0210611

enumerable.empty () : 00 : 00 : 00.0192563

EmptyEnumerator 인스턴스 : 00 : 00 : 00.0012966

using System;
using System.Diagnostics;
using System.Collections;
using System.Linq;

public class Program
{
    private const int Iterations = 190000;
    public static void Main()
    {
        var sw = new Stopwatch();

        sw.Start();
        for (int i = 0; i < Iterations; i++)
        {
            IEnumerator enumerator = YieldBreak();
            while(enumerator.MoveNext())
            {
                throw new InvalidOperationException("Should not occur");
            }           
        }
        sw.Stop();

        Console.WriteLine("Yield break: {0}", sw.Elapsed);

        GC.Collect();

        sw.Restart();
        for (int i = 0; i < Iterations; i++)
        {
            IEnumerator enumerator = Enumerable.Empty<object>().GetEnumerator();
            while(enumerator.MoveNext())
            {
                throw new InvalidOperationException("Should not occur");
            }           
        }
        sw.Stop();

        Console.WriteLine("Enumerable.Empty<T>(): {0}", sw.Elapsed);

        GC.Collect();

        sw.Restart();
        var instance = new EmptyEnumerator();
        for (int i = 0; i < Iterations; i++)
        {
            while(instance.MoveNext())
            {
                throw new InvalidOperationException("Should not occur");
            }           
        }
        sw.Stop();

        Console.WriteLine("EmptyEnumerator instance: {0}", sw.Elapsed);
    }

    public static IEnumerator YieldBreak()
    {
        yield break;
    }

    private class EmptyEnumerator : IEnumerator
    {
        //public static readonly EmptyEnumerator Instance = new EmptyEnumerator();

        public bool MoveNext()
        {
            return false;
        }

        public void Reset()
        {
        }

        public object Current { get { return null; } }
    }
}

내가 사용하는 방법은 빈 배열의 열거자를 사용하는 것입니다.

public IEnumerator GetEnumerator() {
    return new object[0].GetEnumerator();
}

일반 iEenumerator 또는 ienumerable에도 사용할 수 있습니다 (적절한 유형의 배열 사용).

ienumerator 인터페이스 및 ienumerable을 구현하고 ienumerable 인터페이스의 movenext 함수에서 false를 반환 할 수 있습니다.

private class EmptyEnumerator : IEnumerator
{


    public EmptyEnumerator()
    {
    }

    #region IEnumerator Members

    public void Reset() { }

    public object Current
    {
        get
        {
            throw new InvalidOperationException();
        }
    }
    public bool MoveNext()
    { return false; }
}


public class EmptyEnumerable : IEnumerable
{

    public IEnumerator GetEnumerator()
    {
        return new EmptyEnumerator();
    }
}

나는 이것을 다음과 같이 썼다 :

public IEnumerator<T> GetEnumerator()
{
    return this.source?.GetEnumerator() ??
            Enumerable.Empty<T>().GetEnumerator();
}

ienumerator 인터페이스를 구현하는 nullenumerator를 만들 수 있습니다. NullEnumerator에서 인스턴스를 전달할 수 있습니다.

여기 빈민가의 예입니다

이 질문에서 빈 열거자를 얻는 가장 간단한 방법을 찾고 있습니다. 성능을 비교 한 답변을 본 후에는 빈 열거 자 클래스 솔루션을 사용하기로 결정했지만 광산은 다른 예제보다 작고 일반적인 유형이며 기본 인스턴스를 제공하므로 새 인스턴스를 모두 만들 필요가 없습니다. 성능을 더욱 향상시켜야하는 시간.

class EmptyEnumerator<T> : IEnumerator<T>
{
   public readonly static EmptyEnumerator<T> value = new EmptyEnumerator<T>();
   public T Current => throw new InvalidOperationException();
   object IEnumerator.Current => throw new InvalidOperationException();
   public void Dispose() { }
   public bool MoveNext() => false;
   public void Reset() { }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top