Die hier gezeigte Klasse nimmt einen Enumerator (IEnumerator<T>) oder eine Auflistung (IEnumerable<T>) entgegen und durchläuft diese immer wieder im Kreis. Würde mein beispielsweise ein Array mit den Werten 1,2,3 übergeben, würde diese Klasse 1,2,3,1,2,3,1,2,3,1,2,3,... usw. zurück geben.
Mit Hilfe der break-Anweisung in einer foreach-Schleife bzw. passenden LINQ-Methoden oder einem manuellen verwenden der IEnumerator Schnittstelle kann man die "Dauerschleife" wieder anhalten.
Diese Klasse auf GitHub
http://bit.ly/1KdwukE
UnitTests zu diese Klasse auf GitHub
http://bit.ly/1WQ99rd
GFU-Schulungen [Anzeige]
C# 2017/2015/2013 AufbauIn dieser Schulung lernen Sie fortgeschrittene Techniken im Bereich .Net C#. Dabei stehen neben den eigentlichen Techniken auch architektonische Aspekte im Mittelpunkt.
VB.NET EinführungDie Schulung zeigt Ihnen, wie Sie einfache, benutzerorientierte Programme, die auf Datenbanken zugreifen, in VB.NET eigenständig entwickeln.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Koopakiller.Linq
{
public static class Extensions
{
/// <summary>
/// Duchläuft eine Auflistung immer wieder im Kreis.
/// </summary>
/// <typeparam name="T">Der Typ der Elemente in der Auflistung.</typeparam>
/// <param name="source">Die zu durchlaufende Auflistung.</param>
/// <param name="useCache">Wenn <c>true</c> dann wird <paramref name="source"/> nur einmal
/// durchlaufen; andernfalls wird mehrfach über die Auflistung iteriert.</param>
public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, bool useCache = true)
{
if (useCache)
{
source = source.ToList();
}
while (true)
{
// ReSharper disable once PossibleMultipleEnumeration
foreach (var item in source)
{
yield return item;
}
}
// ReSharper disable once FunctionNeverReturns
}
}
public sealed class RingEnumerator<T> : IEnumerable<T>, IEnumerator<T>
{
#region Fields
private readonly IEnumerator<T> _enumerator;
private bool _lastMoveNextWasFalse = true;
private bool _iterationStarted;
private bool _useCache;
private List<T> _cachedList;
private int _currentCachedItemIndex = -1;
private bool _cacheBuildComplete;
#endregion
#region .ctor
public RingEnumerator(IEnumerable<T> source) : this(source?.GetEnumerator()) { }
public RingEnumerator(IEnumerator<T> enumerator)
{
if (enumerator == null)
{
throw new ArgumentNullException(nameof(enumerator), $"{nameof(enumerator)} cannot be null.");
}
this._enumerator = enumerator;
}
#endregion
#region Properties
public bool UseCache
{
get { return this._useCache; }
set
{
if (this._iterationStarted)
{
throw new InvalidOperationException("The enumeration has already started.");
}
this._useCache = value;
}
}
#endregion
#region IEnumerator
object IEnumerator.Current => this.Current;
public T Current
{
get
{
if (this.UseCache && this._cacheBuildComplete)
{
return this._cachedList[this._currentCachedItemIndex];
}
else
{
return this._enumerator.Current;
}
}
}
public void Reset()
{
this._currentCachedItemIndex = -1;
this._cacheBuildComplete = false;
this._iterationStarted = false;
this._enumerator.Reset();
}
public bool MoveNext()
{
if (!this._iterationStarted && this.UseCache)
{
this._cacheBuildComplete = false;
this._cachedList = new List<T>();
}
if (this.UseCache && this._cacheBuildComplete)
{
++this._currentCachedItemIndex;
if (this._currentCachedItemIndex >= this._cachedList.Count)
{
this._currentCachedItemIndex = 0;
}
return true;
}
else
{
this._iterationStarted = true;
if (this._enumerator.MoveNext())
{
this._lastMoveNextWasFalse = false;
if (this.UseCache)
{
this._cachedList.Add(this.Current);
}
return true;
}
if (this.UseCache)
{
this._cacheBuildComplete = true;
this._currentCachedItemIndex = 0;
return this._cachedList.Count > 0;
}
else
{
if (this._lastMoveNextWasFalse)
{
return false;
}
this._lastMoveNextWasFalse = true;
this._enumerator.Reset();
this._enumerator.MoveNext();
return true;
}
}
}
#endregion
#region IDisposable
public void Dispose()
{
this._enumerator.Dispose();
}
#endregion
#region IEnumerable
public IEnumerator<T> GetEnumerator() => this;
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
#endregion
}
}
4 Kommentare zum Snippet