我讀過埃裏克的有關的foreach枚舉和對不同場景的文章here其中的foreach可以工作C#`foreach`行爲 - 澄清?
爲了防止舊的C#版本做拳擊,C#團隊啓用鴨子類型爲的foreach上運行。非IEnumerable集合(A公共GetEnumerator
返回的東西,有公共MoveNext
和Current
屬性是足夠了(
所以,埃裏克寫了sample:
class MyIntegers : IEnumerable
{
public class MyEnumerator : IEnumerator
{
private int index = 0;
object IEnumerator.Current { return this.Current; }
int Current { return index * index; }
public bool MoveNext()
{
if (index > 10) return false;
++index;
return true;
}
}
public MyEnumerator GetEnumerator() { return new MyEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
但我相信它有一些輸入錯誤(缺少訪問者在Current
屬性執行)它阻止它編譯(我已經給他發了電子郵件)。
反正這裏是一個工作版本:
class MyIntegers : IEnumerable
{
public class MyEnumerator : IEnumerator
{
private int index = 0;
public void Reset()
{
throw new NotImplementedException();
}
object IEnumerator.Current {
get { return this.Current; }
}
int Current {
get { return index*index; }
}
public bool MoveNext()
{
if (index > 10) return false;
++index;
return true;
}
}
public MyEnumerator GetEnumerator() { return new MyEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
確定。
根據MSDN:
A型
C
被說成是一個collection type
如果它實現了System.Collections.IEnumerable
接口或通過滿足的以下條件的所有實現collection pattern
:
C包含一個具有簽名GetEnumerator()的公共實例方法,該方法返回結構類型,類類型或接口類型,在以下文本中稱爲E.
E包含具有簽名MoveNext()和返回類型bool的公共實例方法。
E包含一個名爲Current的公共實例屬性,允許讀取當前值。該屬性的類型被認爲是集合類型的元素類型。
好的。讓我們的文檔匹配埃裏克的樣本
Eric的樣品是說是collection type
,因爲它實現了System.Collections.IEnumerable
接口(雖然明確)。但它是不是(!) a collection pattern
由於子彈3:MyEnumerator
確實不是名爲當前的公共實例屬性。
MSDN說:
如果集合表達是實現 集合圖案(如上所定義)的類型,在foreach 語句的膨脹是:
E enumerator = (collection).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
否則,集合表達式是一種實現(!)■ System.IEnumerable,和foreach語句的擴展:
IEnumerator enumerator =
((System.Collections.IEnumerable)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
問題#1
看來,Eric的樣品既沒有實現 collection pattern
也不System.IEnumerable
- 所以它不應該匹配上述條件的任何。
foreach (var element in (new MyIntegers() as IEnumerable))
{
Console.WriteLine(element);
}
問題2
爲什麼我不得不提new MyIntegers() as IEnumerable
:那爲什麼我仍然可以通過迭代呢?它已經IEnumerable的(!),甚至在那之後,是不是編譯器已經通過自身通過鑄造做的工作:
((System.Collections.IEnumerable)(collection)).GetEnumerator() ?
正是在這裏:
IEnumerator enumerator =
((System.Collections.IEnumerable)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
...
那麼,爲什麼它仍然想讓我像易數一樣提及?
現在我們知道這個問題主要是關於'System.IEnumerable'輸入錯誤,我還會提到,這個語言規範應該允許您的示例在沒有投射的情況下通過回退到使用IEnumerable接口。當收集模式部分實現時,規範從未提及引發錯誤(這是我在回答中強調C#5.0規範解釋了此錯誤的原因)。 – Lukazoid