IEnumerable<T> 接口
公开枚举数,该枚举数支持在指定类型的集合上进行简单迭代。
若要浏览此类型的.NET Framework 源代码,请参阅参考源。
程序集: 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: emp empFile.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: emp empFile.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 = " + 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: emp empFile.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 = " + 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