IEnumerable<T> 接口
公開枚舉數,該枚舉數支持在指定類型的集合上進行簡單迭代。
若要瀏覽此類型的.NET Framework 源代碼,請參閱參考源。
命名空間: System.Collections.Generic
程序集: mscorlib(在 mscorlib.dll 中)
public interface IEnumerable<out T> : IEnumerable
類型參數
- out T
-
要枚舉的對象的類型。
此類型參數是協變。即可以使用指定的類型或派生程度更高的類型。有關協變和逆變的詳細信息,請參閱 泛型中的協變和逆變。
IEnumerable<T> 類型公開以下成員。
方法
名稱 | 描述 | |
---|---|---|
![]() ![]() ![]() |
GetEnumerator | 返回一個循環訪問集合的枚舉器。 |
GetEnumerator 詳解
返回一個循環訪問集合的枚舉器。
命名空間: System.Collections.Generic
程序集: mscorlib(mscorlib.dll 中)
語法
IEnumerator<T> GetEnumerator()
返回IEnumerator<T>提供了通過公開來循環訪問集合的能力Current屬性。讀取集合中的數據,但不是能修改集合,您可以使用枚舉器。
最初,枚舉數位於集合中的第一個元素之前。在此位置上,Current是不確定的。因此,您必須調用MoveNext方法使枚舉器前進到之前讀取值的集合的第一個元素Current。
Current返回同一個對象,直到MoveNext作為再次調用MoveNext設置Current到下一個元素。
如果MoveNext越過集合,該枚舉數的末尾將被定位在集合中的最后一個元素之后和MoveNext返回false。當枚舉數位於此位置上,對后續調用MoveNext也會返回false。如果最后一次調用到MoveNext返回false,Current是不確定的。您不能設置Current再次為集合的第一個元素必須改為創建新的枚舉器實例。
一個枚舉器沒有對集合的獨占訪問,因此,只要集合保持不變,枚舉器保持有效。如果進行了更改到集合中,如添加、 修改,或刪除元素),則枚舉器將失效,並可能會收到意外的結果時。此外,對集合進行枚舉不是線程安全過程。若要保證線程安全,您應枚舉期間鎖定集合,或實現同步對集合。
集合中的默認實現System.Collections.Generic命名空間時不同步。
using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Linq; public class App { // Excercise the Iterator and show that it's more // performant. public static void Main() { TestStreamReaderEnumerable(); Console.WriteLine("---"); TestReadingFile(); } public static void TestStreamReaderEnumerable() { // Check the memory before the iterator is used. long memoryBefore = GC.GetTotalMemory(true); IEnumerable<String> stringsFound; // Open a file with the StreamReaderEnumerable and check for a string. try { stringsFound = from line in new StreamReaderEnumerable(@"c:\temp\tempFile.txt") where line.Contains("string to search for") select line; Console.WriteLine("Found: " + stringsFound.Count()); } catch (FileNotFoundException) { Console.WriteLine(@"This example requires a file named C:\temp\tempFile.txt."); return; } // Check the memory after the iterator and output it to the console. long memoryAfter = GC.GetTotalMemory(false); Console.WriteLine("Memory Used With Iterator = \t" + string.Format(((memoryAfter - memoryBefore) / 1000).ToString(), "n") + "kb"); } public static void TestReadingFile() { long memoryBefore = GC.GetTotalMemory(true); StreamReader sr; try { sr = File.OpenText("c:\\temp\\tempFile.txt"); } catch (FileNotFoundException) { Console.WriteLine(@"This example requires a file named C:\temp\tempFile.txt."); return; } // Add the file contents to a generic list of strings. List<string> fileContents = new List<string>(); while (!sr.EndOfStream) { fileContents.Add(sr.ReadLine()); } // Check for the string. var stringsFound = from line in fileContents where line.Contains("string to search for") select line; sr.Close(); Console.WriteLine("Found: " + stringsFound.Count()); // Check the memory after when the iterator is not used, and output it to the console. long memoryAfter = GC.GetTotalMemory(false); Console.WriteLine("Memory Used Without Iterator = \t" + string.Format(((memoryAfter - memoryBefore) / 1000).ToString(), "n") + "kb"); } } // A custom class that implements IEnumerable(T). When you implement IEnumerable(T), // you must also implement IEnumerable and IEnumerator(T). public class StreamReaderEnumerable : IEnumerable<string> { private string _filePath; public StreamReaderEnumerable(string filePath) { _filePath = filePath; } // Must implement GetEnumerator, which returns a new StreamReaderEnumerator. public IEnumerator<string> GetEnumerator() { return new StreamReaderEnumerator(_filePath); } // Must also implement IEnumerable.GetEnumerator, but implement as a private method. private IEnumerator GetEnumerator1() { return this.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator1(); } } // When you implement IEnumerable(T), you must also implement IEnumerator(T), // which will walk through the contents of the file one line at a time. // Implementing IEnumerator(T) requires that you implement IEnumerator and IDisposable. public class StreamReaderEnumerator : IEnumerator<string> { private StreamReader _sr; public StreamReaderEnumerator(string filePath) { _sr = new StreamReader(filePath); } private string _current; // Implement the IEnumerator(T).Current publicly, but implement // IEnumerator.Current, which is also required, privately. public string Current { get { if (_sr == null || _current == null) { throw new InvalidOperationException(); } return _current; } } private object Current1 { get { return this.Current; } } object IEnumerator.Current { get { return Current1; } } // Implement MoveNext and Reset, which are required by IEnumerator. public bool MoveNext() { _current = _sr.ReadLine(); if (_current == null) return false; return true; } public void Reset() { _sr.DiscardBufferedData(); _sr.BaseStream.Seek(0, SeekOrigin.Begin); _current = null; } // Implement IDisposable, which is also implemented by IEnumerator(T). private bool disposedValue = false; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!this.disposedValue) { if (disposing) { // Dispose of managed resources. } _current = null; if (_sr != null) { _sr.Close(); _sr.Dispose(); } } this.disposedValue = true; } ~StreamReaderEnumerator() { Dispose(false); } } // This example displays output similar to the following: // Found: 2 // Memory Used With Iterator = 33kb // --- // Found: 2 // Memory Used Without Iterator = 206kb