如何使我的 InfiniteLoopingList class 实现 IEnumerable?
How to make my InfiniteLoopingList class implement IEnumerable?
我正在制作原型应用程序,为此我设计了一个 class,它的行为类似于无限循环列表。也就是说,如果我的内部列表包含 100 个值,当我请求第 101 个值时,我得到第一个,第 102 个得到第二个,依此类推,重复。
所以我想写下面的代码:
var slice = loopingListInstance.Skip(123).Take(5);
据我所知,为此我需要实施合适的 IEnumerable。
这是我当前的代码:
public class InfiniteLoopingList : IEnumerable<double>
{
double[] _values = File.ReadLines(@"c:\file.txt")
.Select(s => double.Parse(s, CultureInfo.InvariantCulture))
.ToArray();
int _size;
public InfiniteLoopingList()
{
_size = _values.Length;
}
public double this[int i]
{
get { return _values[i % _size]; }
set { _values[i % _size] = value; }
}
public IEnumerator<double> GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
// ???? now what ?? :(
}
}
你不需要 class 这个...
扩展方法可以解决问题:
public static class InfEx
{
public static IEnumerable<T> LoopForever<T>(this IEnumerable<T> src)
{
var data = new List<T>();
foreach(var item in src)
{
data.Add(item);
yield return item;
}
for(;;)
{
foreach(var item in data)
{
yield return item;
}
}
}
}
现在您可以将一个序列变成一个循环的无限序列:
IEnumerable<Foo> mySeq = ...;
IEnumerable<Foo> infMySeq = mySeq.LoopForver();
IEnumerable<Foo> aSelectionOfInfMySeq = infMySeq.Skip(101).Take(5);
您可以实现 IEnumerator 接口:
class InifniteEnumerator<T> : IEnumerator<T> {
private int index = -1;
private IList<T> innerList;
private int repeatPos;
public InifniteEnumerator(IList<T> innerList, int repeatPos) {
this.innerList = innerList;
this.repeatPos = repeatPos;
}
public T Current {
get {
if (index == -1) {
throw new InvalidOperationException();
}
return this.innerList[index];
}
}
object IEnumerator.Current {
get {
return this.Current;
}
}
public void Dispose() {
}
public bool MoveNext() {
this.index++;
if (this.index == repeatPos) {
this.index = 0;
}
return true;
}
public void Reset() {
this.index = -1;
}
}
然后 return 它在 GetEnumerator 方法中的一个实例:
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
public IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new InifniteEnumerator(this, 100);
}
由于您实施了索引器 属性,您可以通过以下最简单的方式完成:
public IEnumerator<double> GetEnumerator()
{
int i = 0;
while (true)
yield return this[i++];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
编辑
请注意,这并不是真正的无限循环。此方法仅在 i = int.MaxValue
之前有效。感谢@oleksii。
我正在制作原型应用程序,为此我设计了一个 class,它的行为类似于无限循环列表。也就是说,如果我的内部列表包含 100 个值,当我请求第 101 个值时,我得到第一个,第 102 个得到第二个,依此类推,重复。
所以我想写下面的代码:
var slice = loopingListInstance.Skip(123).Take(5);
据我所知,为此我需要实施合适的 IEnumerable。
这是我当前的代码:
public class InfiniteLoopingList : IEnumerable<double>
{
double[] _values = File.ReadLines(@"c:\file.txt")
.Select(s => double.Parse(s, CultureInfo.InvariantCulture))
.ToArray();
int _size;
public InfiniteLoopingList()
{
_size = _values.Length;
}
public double this[int i]
{
get { return _values[i % _size]; }
set { _values[i % _size] = value; }
}
public IEnumerator<double> GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
// ???? now what ?? :(
}
}
你不需要 class 这个...
扩展方法可以解决问题:
public static class InfEx
{
public static IEnumerable<T> LoopForever<T>(this IEnumerable<T> src)
{
var data = new List<T>();
foreach(var item in src)
{
data.Add(item);
yield return item;
}
for(;;)
{
foreach(var item in data)
{
yield return item;
}
}
}
}
现在您可以将一个序列变成一个循环的无限序列:
IEnumerable<Foo> mySeq = ...;
IEnumerable<Foo> infMySeq = mySeq.LoopForver();
IEnumerable<Foo> aSelectionOfInfMySeq = infMySeq.Skip(101).Take(5);
您可以实现 IEnumerator 接口:
class InifniteEnumerator<T> : IEnumerator<T> {
private int index = -1;
private IList<T> innerList;
private int repeatPos;
public InifniteEnumerator(IList<T> innerList, int repeatPos) {
this.innerList = innerList;
this.repeatPos = repeatPos;
}
public T Current {
get {
if (index == -1) {
throw new InvalidOperationException();
}
return this.innerList[index];
}
}
object IEnumerator.Current {
get {
return this.Current;
}
}
public void Dispose() {
}
public bool MoveNext() {
this.index++;
if (this.index == repeatPos) {
this.index = 0;
}
return true;
}
public void Reset() {
this.index = -1;
}
}
然后 return 它在 GetEnumerator 方法中的一个实例:
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
public IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new InifniteEnumerator(this, 100);
}
由于您实施了索引器 属性,您可以通过以下最简单的方式完成:
public IEnumerator<double> GetEnumerator()
{
int i = 0;
while (true)
yield return this[i++];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
编辑
请注意,这并不是真正的无限循环。此方法仅在 i = int.MaxValue
之前有效。感谢@oleksii。