IEnumerable<T>.GetEnumerator 方法
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
傳回逐一查看集合的列舉值。
public:
System::Collections::Generic::IEnumerator<T> ^ GetEnumerator();
public System.Collections.Generic.IEnumerator<out T> GetEnumerator ();
public System.Collections.Generic.IEnumerator<T> GetEnumerator ();
abstract member GetEnumerator : unit -> System.Collections.Generic.IEnumerator<'T>
Public Function GetEnumerator () As IEnumerator(Of Out T)
Public Function GetEnumerator () As IEnumerator(Of T)
傳回
可用來逐一查看集合的列舉值。
範例
下列範例示範如何實 IEnumerable<T> 作 介面,並使用該實作來建立LINQ查詢。 當您實作 IEnumerable<T>時,您也必須實 IEnumerator<T> 作 或,僅適用於 C#,您可以使用 yield 關鍵詞。 實作 IEnumerator<T> 也需要 IDisposable 實作,您會在此範例中看到此範例。
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class App
{
// Exercise 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(disposing: 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(disposing: false);
}
}
// This example displays output similar to the following:
// Found: 2
// Memory Used With Iterator = 33kb
// ---
// Found: 2
// Memory Used Without Iterator = 206kb
Imports System.IO
Imports System.Collections
Imports System.Collections.Generic
Imports System.Linq
Public Module App
' Excercise the Iterator and show that it's more performant.
Public Sub Main()
TestStreamReaderEnumerable()
Console.WriteLine("---")
TestReadingFile()
End Sub
Public Sub TestStreamReaderEnumerable()
' Check the memory before the iterator is used.
Dim memoryBefore As Long = GC.GetTotalMemory(true)
Dim stringsFound As IEnumerable(Of String)
' 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: {0}", stringsFound.Count())
Catch e As FileNotFoundException
Console.WriteLine("This example requires a file named C:\temp\tempFile.txt.")
Return
End Try
' Check the memory after the iterator and output it to the console.
Dim memoryAfter As Long = GC.GetTotalMemory(false)
Console.WriteLine("Memory Used with Iterator = {1}{0} kb",
(memoryAfter - memoryBefore)\1000, vbTab)
End Sub
Public Sub TestReadingFile()
Dim memoryBefore As Long = GC.GetTotalMemory(true)
Dim sr As StreamReader
Try
sr = File.OpenText("c:\temp\tempFile.txt")
Catch e As FileNotFoundException
Console.WriteLine("This example requires a file named C:\temp\tempFile.txt.")
Return
End Try
' Add the file contents to a generic list of strings.
Dim fileContents As New List(Of String)()
Do While Not sr.EndOfStream
fileContents.Add(sr.ReadLine())
Loop
' Check for the string.
Dim stringsFound =
from line in fileContents
where line.Contains("string to search for")
select line
sr.Close()
Console.WriteLine("Found: {0}", stringsFound.Count())
' Check the memory after when the iterator is not used, and output it to the console.
Dim memoryAfter As Long = GC.GetTotalMemory(False)
Console.WriteLine("Memory Used without Iterator = {1}{0} kb",
(memoryAfter - memoryBefore)\1000, vbTab)
End Sub
End Module
' A custom class that implements IEnumerable(T). When you implement IEnumerable(T),
' you must also implement IEnumerable and IEnumerator(T).
Public Class StreamReaderEnumerable : Implements IEnumerable(Of String)
Private _filePath As String
Public Sub New(filePath As String)
_filePath = filePath
End Sub
' Must implement GetEnumerator, which returns a new StreamReaderEnumerator.
Public Function GetEnumerator() As IEnumerator(Of String) _
Implements IEnumerable(Of String).GetEnumerator
Return New StreamReaderEnumerator(_filePath)
End Function
' Must also implement IEnumerable.GetEnumerator, but implement as a private method.
Private Function GetEnumerator1() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return Me.GetEnumerator()
End Function
End Class
' 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 : Implements IEnumerator(Of String)
Private _sr As StreamReader
Public Sub New(filePath As String)
_sr = New StreamReader(filePath)
End Sub
Private _current As String
' Implement the IEnumerator(T).Current Publicly, but implement
' IEnumerator.Current, which is also required, privately.
Public ReadOnly Property Current As String _
Implements IEnumerator(Of String).Current
Get
If _sr Is Nothing OrElse _current Is Nothing
Throw New InvalidOperationException()
End If
Return _current
End Get
End Property
Private ReadOnly Property Current1 As Object _
Implements IEnumerator.Current
Get
Return Me.Current
End Get
End Property
' Implement MoveNext and Reset, which are required by IEnumerator.
Public Function MoveNext() As Boolean _
Implements IEnumerator.MoveNext
_current = _sr.ReadLine()
if _current Is Nothing Then Return False
Return True
End Function
Public Sub Reset() _
Implements IEnumerator.Reset
_sr.DiscardBufferedData()
_sr.BaseStream.Seek(0, SeekOrigin.Begin)
_current = Nothing
End Sub
' Implement IDisposable, which is also implemented by IEnumerator(T).
Private disposedValue As Boolean = False
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' Dispose of managed resources.
End If
_current = Nothing
If _sr IsNot Nothing Then
_sr.Close()
_sr.Dispose()
End If
End If
Me.disposedValue = True
End Sub
Protected Overrides Sub Finalize()
Dispose(disposing:=False)
End Sub
End Class
' This example displays output similar to the following:
' Found: 2
' Memory Used With Iterator = 33kb
' ---
' Found: 2
' Memory Used Without Iterator = 206kb
備註
傳回的功能 IEnumerator<T> 可讓您藉由公開 屬性來逐一 Current 查看集合。您可以使用列舉值來讀取集合中的數據,但不能修改集合。
一開始,列舉程式位在集合中的第一個項目之前。 在這個位置上,Current 並未定義。 因此,您必須呼叫 MoveNext 方法,將列舉值前進至集合的第一個專案,再讀取的值 Current。
Current 會傳回相同的物件,直到 MoveNext 再次呼叫 為 MoveNext 下一個專案的 集合 Current 為止。
如果 MoveNext 傳遞集合的結尾,列舉值會放置在集合的最後一個專案後面,並 MoveNext 傳 false
回 。 當列舉值位於這個位置時,後續呼叫 MoveNext 也會傳回 false
。 如果最後一次 MoveNext 呼叫傳 false
回 , Current 則為未定義。 您不能再次將 Current 設定為集合的第一個項目;您必須建立新的列舉值執行個體。
如果對集合進行變更,例如新增、修改或刪除專案,列舉值的行為就會未定義。
列舉值沒有集合的獨佔存取權,因此只要集合保持不變,列舉值就會保持有效。 如果對集合進行變更,例如新增、修改或刪除元素,列舉值就會失效,而且您可能會得到非預期的結果。 此外,列舉集合不是安全線程的程式。 若要保證線程安全,您應該在列舉值期間鎖定集合,或在集合上實作同步處理。
命名空間中 System.Collections.Generic 集合的預設實作不會同步處理。