2010-10-16 74 views
8

讓我們有這樣的代碼:當調用IEnumerator.Reset()方法時?

class MyList : IEnumerable, IEnumerator 
{ 
    int[] A = { 1, 2, 3, 4, 5 }; 
    int i = -1; 

    #region IEnumerator Members 

    public object Current 
    { 
     get { return A[i]; } 
    } 

    public bool MoveNext() 
    { 
     i++; 
     return i < 5; 
    } 

    public void Reset() 
    { 
     i = -1; 
    } 

    #endregion 

    #region IEnumerable Members 

    public IEnumerator GetEnumerator() 
    { 
     return (IEnumerator)this; 
    } 

    #endregion 
} 

並在主要方法:

MyList list = new MyList(); 
foreach (int i in list) 
{ 
    Console.WriteLine(i); 
} 

foreach (int i in list) 
{ 
    Console.WriteLine(i); 
} 

爲什麼第二foerach不起作用?和「我」不會再次初始化?

是這樣的:Reset方法應該在執行foreach之前自動調用?

爲什麼它不會在這裏打電話?

+2

有沒有解決? :( – 2010-10-16 05:56:02

+1

我認爲它只存在與COM的互操作性,普通的.net代碼不會使用它,幾乎所有的實現都會拋出異常 – CodesInChaos 2010-10-16 10:37:07

回答

6

IEnumerable和IEnumerator通常應該是單獨的類,並且除了總是返回空或總是返回相同項的枚舉數的情況外,GetEnumerator方法必須始終返回IEnumerator的新實例。

IEnumerator.Reset沒有多少意義; for-each循環不使用它,並且IEnumerable/IEnumerator的使用者不能使用它,除非他們知道可枚舉類型是什麼,在這種情況下,它們可以使用實際類型而不是界面。

+0

如果有人實現了MoveNext方法,那麼當它返回假,在這個調用之前重置是一種不好的做法?如果是這樣,爲什麼他們把重置放入界面? – jannagy02 2013-10-20 07:54:19

+0

@ jannagy02:.NET有很多方面應該被視爲進化/或折衷的殘留產品。有些人從來沒有經過深思熟慮。其他人在設計的一個階段可能是明智而有用的部分,但在設計的其他部分重新設計時變得毫無用處。有時候,事情會通過設計過程發展,即使是涉及設計的人也可能不記得哪些部分是經過思考的,哪些是一起投入的。 – supercat 2013-10-21 15:05:36

3

復位不被foreach調用。在Reflector中查看你的Main方法來確認這一點。

.NET類,如ArrayList,實際上返回實現IEnumerator的類的新實例。

例如ArrayList實現IEnumerable,其GetEnumerator方法是這樣的:

public virtual IEnumerator GetEnumerator() 
{ 
    return new ArrayListEnumeratorSimple(this); 
} 

所以沒有必要擔心調用復位,因爲每次的foreach使用枚舉的新實例。

有關顯示IEnumerable的實現和實現IEnumerator的單獨類的完整示例,您可以查看IEnumerable的文檔。

9

重置是多餘的;以至於在迭代器塊的語言規範中要求要求在復位時拋出異常。正確的做法是簡單地放置並釋放舊的迭代器,然後再次調用GetEnumerator。或者更好:避免讀取兩次,因爲並非所有數據都是可重複的。

+1

你有鏈接說它應該拋出異常嗎?我想詳細閱讀。 – GiddyUpHorsey 2011-12-02 01:57:39

+0

嗯......找到[this](http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx)。顯然'Reset'只存在於COM互操作性中。在我看來,它本來不應該在界面上被定義。 – GiddyUpHorsey 2011-12-02 02:03:28

+0

如果定義更好,重置不會是多餘的。如果有一個'general'IEnumerable和一個IMultipassEnumerable,它從它繼承並返回一個實現Reset的IMultipassEnumerator,那麼它可能具有使用相同枚舉器重複枚舉的語義,即可保證返回相同的結果收藏改變了;相反,如果有人每次使用兩個單獨的統計員,他們可能會很好地返回不同的結果。 – supercat 2011-12-23 18:07:41

2

這也適用於:

public bool MoveNext() 
{ 
     if(i < 5) 
     { 
      i++; 
      return true; 
     } 
     else 
     { 
      i = -1; 
      return false; 
     } 
} 
-1

有,我需要做這許多情況下,所以我要做的就是在我的GetEnumerator方法調用復位。這裏是一個例子:

public IEnumerator GetEnumerator() 
{ 
    this.Reset(); // Reset each time you get the Enumerator 
    return (IEnumerator)this; 
} 
+0

接受的答案要好得多;你不應該讓你的'IEnumerable'每次都返回'IEnumerator'的同一個實例。使用這種方法你不能*有兩個不同的迭代器迭代同一個列表。使用具有多個迭代器的適當的實現根本不是問題。 – Servy 2013-10-14 20:07:46

+0

這是一個很好的觀點。我的回答更直接地反映了兩個不同時期迭代收集的原始問題。 – user2880159 2013-10-15 13:40:01

相關問題