簡體   English   中英

名單 <T> .Enumerator IEnumerator.Reset()方法實現

[英]List<T>.Enumerator IEnumerator.Reset() method implementation

盡管事實上, 永遠不應該使用IEnumerator.Reset方法,但我在List<T>發現了方法實現的奇怪行為。

無論您如何檢查.NET Framework源代碼(使用參考源和ILSpy進行嘗試),該方法都實現如下:

void System.Collections.IEnumerator.Reset() {
    if (version != list._version) {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }

    index = 0;
    current = default(T);
}

但是,看起來這個方法根本就沒有被調用過! 考慮一下代碼:

var list = new List<int>(1) { 3 };
using (var e = list.GetEnumerator())
{
    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);

    ((IEnumerator)e).Reset();

    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);
}

很明顯,它應該打印True3兩次。 而不是結果

True
3
False
0

我錯過了任何簡單的解釋?

我錯過了任何簡單的解釋?

是的:你在這里裝箱List.Enumerator

((IEnumerator)e).Reset();

這需要現有的副本並重置它 - 將原件保留為一件。

要重置實際的枚舉器,你需要這樣的東西:

var list = new List<int>(1) { 3 };
var e = list.GetEnumerator();
// Can't use "ref" with a using statement
try
{
    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);

    Reset(ref e);

    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);
}
finally
{
    e.Dispose();
}

static void Reset<T>(ref T enumerator) where T : IEnumerator
{
    enumerator.Reset();
}

這很棘手,因為它使用顯式接口實現。

我沒有測試過,但我認為這對你有用。 顯然,這是一個壞主意,要做到這一點?

編輯:或者,只需將您的變量類型更改為IEnumeratorIEnumerator<int>即可。 然后它將被裝箱一次 ,並且Reset方法將改變盒裝值:

var list = new List<int>(1) { 3 };
using (IEnumerator e = list.GetEnumerator())
{
    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);

    e.Reset();

    Console.WriteLine(e.MoveNext());
    Console.WriteLine(e.Current);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM