질문 배경:
Visual Basic의 For Each...Next 문은 컬렉션 또는 배열의 요소를 반복할 수 있도록 해줍니다. VB6부터는 표준 컬렉션에 대해 반복할 수 있었고, VB.NET에서는 특정 인터페이스를 구현하는 모든 유형에 대해 지원됩니다. 그러나 사용자 정의 컬렉션을 만들어야 할 경우에는 적절한 인프라를 구현하는 것이 중요합니다.
문제
단순히 요소 저장만으로는 충분하지 않습니다. For Each 문은 특수한 IEnumerable 인터페이스의 지원이 필요합니다. 종종 사용자 정의 컬렉션 라이브러리는 Add/Get 메서드로 제한되며, 객체는 반복을 위한 "블랙 박스"가 되는 경우가 많습니다. 이는 반복 언어 구조와의 통합을 방해하고 오류를 초래할 수 있습니다.
해결책
For Each가 귀하의 컬렉션에서 정상적으로 작동하려면 IEnumerable 인터페이스를 구현해야 하며, 형식이 지정된 요소와 작업을 지원하려면 IEnumerable(Of T)를 구현해야 합니다. 나만의 열거자(Enumerator)를 만들어서 IEnumerator 인터페이스(또는 제네릭 버전에서 IEnumerator(Of T))를 구현해야 합니다.
예:
Public Class IntCollection Implements IEnumerable(Of Integer) Private ReadOnly items As New List(Of Integer)() Public Sub Add(value As Integer) items.Add(value) End Sub Public Function GetEnumerator() As IEnumerator(Of Integer) _ Implements IEnumerable(Of Integer).GetEnumerator Return items.GetEnumerator() End Function Private Function IEnumerable_GetEnumerator() As IEnumerator _ Implements IEnumerable.GetEnumerator Return GetEnumerator() End Function End Class ' 사용 예: Dim col As New IntCollection() col.Add(10) col.Add(20) col.Add(30) For Each n As Integer In col Console.WriteLine(n) Next
주요 특징:
인터페이스 IEnumerable 없이 메서드 GetEnumerator를 작성하여 For Each를 구현할 수 있습니까?
아니요, Visual Basic은 컬렉션이 For Each와 호환될 수 있도록 IEnumerable/IEnumerable(Of T) 인터페이스의 공식적인 지원이 필요합니다.
열거자는 별도의 클래스여야 합니까?
아니요, 요소 데이터가 표준 열거자를 지원하는 경우(예: List(Of T) 집계 시) 그 GetEnumerator를 반환할 수 있습니다. 복잡한 시나리오에서는 자체 IEnumerator 구현 클래스가 필요할 수 있습니다.
For Each 루프 내에서 컬렉션을 수정할 수 있습니까?
아니요, 반복 중에 컬렉션을 변경하면 InvalidOperationException이 발생합니다. 이를 올바르게 처리하려면 특별한 전략이 필요합니다(예: 반복 전에 목록 복사 또는 인덱싱 사용).
회사에서 배열을 통한 추가 및 삭제 기능을 갖춘 MyCollection라는 자체 클래스를 개발했지만, IEnumerable 인터페이스를 구현하지 않았습니다. For Each가 작동하지 않아 일반적인 루프와 요소가 포함된 공개 필드를 사용해야 했습니다.
장점:
단점:
컬렉션 클래스를 리팩토링하여 IEnumerable(Of T)를 구현했습니다. 그 후 컬렉션은 쉽게 For Each에서 사용되었고, LINQ와의 호환성도 확보했습니다.
장점:
단점: