爲什麼x.Current永遠等於空?
簡短的回答:布賴恩Kernighan的說,「你的編譯器是對語言的最終權威」 。它這樣做是因爲微軟的這些人以這種方式編寫了代碼。正如我們將在下面看到的,在這種情況下,這是由實施者決定的。用傳說中的計算機科學家Ray Dorset的話說,「只要做你自己感覺的事情」。
但這裏還是有一些有趣的地方。 According to MSDN,
如果上次調用MoveNext返回false,則Current未定義。
這是通用的IEnumerator<T>
,你正在使用的。這是你的問題的答案。
在某些語言中,例如JavaScript,「undefined」是一個關鍵字。在其他情況下,這是一個純英文單詞,用於描述規範留下的內容。如果他們說C或C#中的行爲是「未定義的」,則表示它取決於實施者。
以上不同從nongenericIEnumerator
的記錄的行爲:
如果對MoveNext的最後一次調用返回false,調用當前拋出異常。
所有它告訴你的是,與一般的IEnumerator<T>
,後MoveNext()
返回false,Current
可以做任何實施者感覺就像使它做。它可能會返回default(T)
(這就是我所要做的),但它可能會返回最後一個項目。我會毫不猶豫地讓它拋出一個異常,因爲我們已經有不止一個的Microsoft .NET代碼(你發現的那個,以及你將要見到的幾個代碼)不會拋出,而且MSDN並沒有說它可能,所以採取這個意思,它只是沒有。
I tested some other cases:
public class Program
{
public static void Main()
{
//var x = GetEnumeratorNonGeneric(1);
//var x = GetEnumerator(1);
//var x = GetEnumeratorInt(1);
//var x = GetEnumeratorIntRangeSelect(1);
var x = GetEnumeratorIntList(1);
for (int i = 0; i < 2; ++i)
{
var isMoving = x.MoveNext();
Console.WriteLine($"Cursor moved: {isMoving}");
Console.WriteLine($"Current element is null: {x.Current == null}");
Console.WriteLine($"Current element: {x.Current}");
}
}
static IEnumerator<String> GetEnumerator(int count)
{
return Enumerable.Range(1, count).Select(n => n.ToString()).GetEnumerator();
}
static IEnumerator<int> GetEnumeratorInt(int count)
{
return Enumerable.Range(1, count).GetEnumerator();
}
static IEnumerator<int> GetEnumeratorIntRangeSelect(int count)
{
return Enumerable.Range(1, count).Select(n => n).GetEnumerator();
}
static IEnumerator<int> GetEnumeratorIntList(int count)
{
return Enumerable.Range(1, count).ToList().GetEnumerator();
}
static IEnumerator GetEnumeratorNonGeneric(int count)
{
return new ArrayList(Enumerable.Range(1, count).Select(n => n.ToString()).ToArray()).GetEnumerator();
}
}
輸出爲GetEnumeratorNonGeneric()
:從GetEnumerator()
Cursor moved: True
Current element is null: False
Current element: 1
Cursor moved: False
Run-time exception (line -1): Enumeration already finished.
Stack Trace:
[System.InvalidOperationException: Enumeration already finished.]
輸出。這不會拋出,但在這種情況下確實返回default(T)
,null
。
Cursor moved: True
Current element is null: False
Current element: 1
Cursor moved: False
Current element is null: True
Current element:
從GetEnumeratorInt()
輸出。 Enumerable.Range()
返回使用的最後一個值Current
枚舉:
Cursor moved: True
Current element is null: False
Current element: 1
Cursor moved: False
Current element is null: False
Current element: 1
隨着GetEnumeratorIntRangeSelect()
,我們發現Select()
獲得我們的枚舉,其Current
回報default(T)
後MoveNext()
返回false。這與上面的GetEnumerator()
真的是多餘的,但它說明了值類型而不是引用類型會發生什麼。
Cursor moved: True
Current element is null: False
Current element: 1
Cursor moved: False
Current element is null: False
Current element: 0
的List<T>
枚舉我們從調用ToList()
獲得也Current
結束後返回default(T)
。
我沒有在結束後發現在Current
上拋出的通用IEnumerator<T>
,但正如您所看到的,我沒有找到一個好項目來尋找它。
或者類似的話;我找不到確切的措辭。
可能不是真正的計算機科學家。
爲了將來的參考,這裏標籤的目的是引起人們對你的問題的關注。只有監控「xelement」和「ienumerator」標籤的人才會看到您的問題 - 幾乎沒有人。我在原始的新問題清單中偶然看到了這個問題,但是有太多的問題出現,因此任何人都不會注意到任何特定問題。如果你給C#添加了標籤(我冒昧),那麼你就可以在可能回答它的人面前獲得它。我意識到這似乎有點違反直覺,但這是網站最終被使用的方式。 –
感謝您的建議Ed。我會忍受它。我很幸運,你偶然發現我的問題,因爲你的回答是完美的:) – Pasato