如何迭代实现 IEnumerator<T> 的自定义集合?

问题描述 投票:0回答:1

我想使用 C# 迭代自定义集合的值。

我创建了一个名为

MyLinkedList
的集合来表示这样的自定义链表

public class MyLinkedList<T> : IEnumerable<T?> where T : IEquatable<T?>
{
    // other methods are removed for simplicity. 

    IEnumerator<T?> IEnumerable<T?>.GetEnumerator()
        => new MyLinkedListNodeEnumerator<T>(_root);

    public IEnumerator GetEnumerator()
        => new MyLinkedListNodeEnumerator<T>(_root);
}

我实现了

IEnumerable<T?>
接口,因此我可以使用
foreach
循环来迭代自定义集合中的值。这是
MyLinkedListNodeEnumerator

的实现
public class MyLinkedListNodeEnumerator<T>(MyLinkedListNode<T>? root)
    : IEnumerator<T?> where T : IEquatable<T?>
{
    private readonly MyLinkedListNode<T>? _root = root;

    private MyLinkedListNode<T>? _current = root;

    public object? Current
    {
        get
        {
            var current = _current;

            _current = _current!.Next;

            return current;
        }
    }

    T? IEnumerator<T?>.Current
    {
        get
        {
            var current = _current;

            _current = _current!.Next;

            return current!.Data;
        }
    }

    public void Dispose()
    {

    }

    public bool MoveNext()
        => _current?.Next != null;

    public void Reset()
    {
        _current = _root;
    }
}

这是一个用例示例,

var list = new MyLinkedList<int>();
list.InsertFirst(10);
list.InsertNext(20);
list.InsertNext(30);

当我循环枚举器对象时,我期望每个项目都是

int
类型,因为这是创建列表的通用类型。所以
foreach
使用的是
IEnumerator GetEnumerator()
而不是
IEnumerable<T?>.GetEnumerator()

foreach(var item in list) 
{
    // here item is an object of a type MyLinkedListNode<int> 
    // not int as I am expecting.
}

如何确保

foreach
将使用
IEnumerable<T?>.GetEnumerator()
,以便我可以迭代
int
值?

c# loops ienumerable
1个回答
0
投票

不知道您的具体情况

MyLinkedListNode
:

public class MyLinkedListNodeEnumerator<T>()
    : IEnumerator<T> where T : IEquatable<T>
{
    private MyLinkedListNode<T> _root;
    private MyLinkedListNode<T> _current = null;

    public MyLinkedListNodeEnumerator(MyLinkedListNode<T> root)
        => _root = root;

    T Current
        => _current.Data;

    object IEnumerator.Current
        => _current.Data;

    public bool MoveNext()
    {
        _current = (_current ?? _root).Next;
        return _current is not null;
    }

    public void Reset()
        => _current = null;

    public void Dispose()
    { }
}

请注意,

Current
是幂等的,不应修改枚举器。向前移动枚举器的唯一方法是使用
MoveNext
。在初始状态下,枚举器应该在第一个元素之前开始,这就是为什么 _current
null
开始。此外,未定义在先前未成功调用
Current
的情况下访问
MoveNext
    

© www.soinside.com 2019 - 2024. All rights reserved.