2011-09-05 69 views
48

我無法記住在C#中如何使用IEnumerator(但不是爲什麼)。我習慣了Java,它有很好的文檔,可以很好地解釋初學者的一切。所以,請容忍我。簡單IEnumerator使用(使用示例)

我已經嘗試從這些板上的其他答案學習無濟於事。我沒有提出一個已經被問過的通用問題,而是一個具體的例子,可以爲我闡明一些事情。

假設我有一個方法需要傳遞一個IEnumerable<String>對象。所有方法都需要將字母roxxors連接到迭代器中每個String的末尾。然後它會返回這個新的迭代器(當然原來的IEnumerable對象保持原樣)。

我該怎麼辦?當然,除了我之外,這裏的答案應該可以幫助許多人解決關於這些對象的基本問題。

回答

78

以下是關於IEnumerator的文檔。它們用於獲取列表的值,其中的長度不一定是提前知道的(儘管它可能是)。這個詞來自enumerate,意思是「一個一個地計數或命名」。

IEnumeratorIEnumerator<T>由所有IEnumerableIEnumerable<T>接口提供經由GetEnumerator()在.NET(後者提供兩者)。這很重要,因爲foreach語句旨在通過這些接口方法直接與枚舉器一起工作。

因此,例如:

IEnumerator enumerator = enumerable.GetEnumerator(); 

while (enumerator.MoveNext()) 
{ 
    object item = enumerator.Current; 
    // Perform logic on the item 
} 

變爲:

foreach(object item in enumerable) 
{ 
    // Perform logic on the item 
} 

至於您的具體方案,幾乎在.NET所有集合實施IEnumerable。正因爲如此,你可以做到以下幾點:

public IEnumerator Enumerate(IEnumerable enumerable) 
{ 
    // List implements IEnumerable, but could be any collection. 
    List<string> list = new List<string>(); 

    foreach(string value in enumerable) 
    { 
     list.Add(value + "roxxors"); 
    } 
    return list.GetEnumerator(); 
} 
+0

重置()不被foreach調用。它意味着COM互操作,並不是所有的枚舉器都支持它(實際上大多數枚舉器*不支持它)。 –

+0

統計員是隻讀的,對嗎?我怎樣才能返回一個包含我的修改使用這種模式的枚舉類型? – BlackVegetable

+0

@Martinho你是對的。 –

5

我會做這樣的事情:

private IEnumerable<string> DoWork(IEnumerable<string> data) 
{ 
    List<string> newData = new List<string>(); 
    foreach(string item in data) 
    { 
     newData.Add(item + "roxxors"); 
    } 
    return newData; 
} 

簡單的東西:)

+0

這是我的第一個念頭。但是,其他與我交互的方法要求我返回IEnumerable類型或其他類型。儘管謝謝你的迴應! – BlackVegetable

+0

@BlackVegetable:'列表'是一個'IEnumerable '。但是,是的,有更好的方法來做到這一點(使用'yield')。 –

+1

我似乎記得,你應該儘量不要在聲明爲IEnumerable的方法中返回一個List。原因是人們可能會「欺騙」並注意到它實際上是一個列表,並開始用它列出所有事情。列表(實際上所有IEnumerables)確實有一個AsEnumerable()方法,我認爲它應該被調用並返回。 – Chris

8

如果我理解正確,那麼在C#編譯器yield return神奇的是你所需要的,我認爲。

例如

IEnumerable<string> myMethod(IEnumerable<string> sequence) 
{ 
    foreach(string item in sequence) 
    { 
     yield return item + "roxxors"; 
    } 
} 
+0

因此,在這種情況下,yield會在每次運行時從列表中返回一個(已修改的)字符串?或者它會返回某種IEnumerable對象? – BlackVegetable

+0

@BlackVegetable是的,它會返回一個'IEnumerable'對象,每次調用MoveNext'時(直接或間接使用foreach)將會生成一個字符串 –

+0

是的,它是語法糖,它告訴編譯器把它到一個迭代器塊中。看到這裏http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx –

12
public IEnumerable<string> Appender(IEnumerable<string> strings) 
{ 
    List<string> myList = new List<string>(); 
    foreach(string str in strings) 
    { 
     myList.Add(str + "roxxors"); 
    } 
    return myList; 
} 

或使用yield construct

public IEnumerable<string> Appender(IEnumerable<string> strings) 
{ 
    foreach(string str in strings) 
    { 
     yield return str + "roxxors"; 
    } 
} 

,或者乾脆

var newCollection = strings.Select(str => str + "roxxors"); //(*) 

var newCollection = from str in strings select str + "roxxors"; //(**) 

其中後兩者使用LINQ(**)只是(*)的語法糖。

+0

與LINQ有趣的模式。我必須研究這一點。謝謝大家的快速幫助! – BlackVegetable

+0

我似乎記得你應該儘量不要在IEnumerable聲明的方法中返回一個List。原因是人們可能會「欺騙」並注意到它實際上是一個列表,並開始用它列出所有事情。列表(實際上所有IEnumerables)確實有一個AsEnumerable()方法,我認爲它應該被調用並返回。否則,最好的答案是收益率,特別是林克的回答。 :) – Chris

+0

如果你打算在C#中進行大量的開發,你一定會想在LINQ上投入一些時間 - 它會爲你節省大量的時間並讓你對代碼感覺更好:-) – Rune

4

你也可以使用LINQ的選擇方法:

var source = new[] { "Line 1", "Line 2" }; 

var result = source.Select(s => s + " roxxors"); 

在這裏閱讀更多Enumerable.Select Method