문제
무엇보다도 "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() { }
}