컬렉션 사용할 때 주의할 점

비주얼베이직 닷넷으로 프로그래밍할 때 컬렉션을  사용하면 간편하게 개체 집합을 다룰 수 있다. 컬렉션을 주로 For Each…Next 문과 함께 사용하게 되는데, 다음의 내용을 주의해야 한다.

  • 컬렉션 수정 불가. GetEnumerator에서 반환된 열거자 개체를 사용하여 요소를 추가하거나 삭제하거나 바꾸거나 다시 정렬하여 컬렉션을 변경할 수는 없다. For EachNext 루프를 시작한 다음 컬렉션을 변경하면 열거자 개체는 유효하지 않게 되고, 다음에 요소에 액세스하려고 하면InvalidOperationException 예외가 발생한다.
  • 컬렉션 요소 수정 불가. 열거자 개체의 Current 속성은 ReadOnly(Visual Basic)이며 각 컬렉션 요소의 로컬 복사본을 반환한다. 이것은 For EachNext 루프에서 요소 자체를 수정할 수 없음을 의미한다. 모든 수정 내용은 Current의 로컬 복사본에만 영향을 주며 내부 컬렉션에 반영되지는 않는다.(중요!)  그러나 요소가 참조 형식인 경우에는 요소가 가리키는 인스턴스의 멤버를 수정할 수 있다. 다음은 이에 대한 예이다.

[vbnet]Public Overrides Sub LinkTo(ByVal BuildingDB As BuildingLibrary)
For Each myItem As Layer In Me.Layers
If BuildingDB.FloorMaterials.ContainsKey(myItem.Material.Name) Then
myItem.Material = BuildingDB.FloorMaterials(myItem.Material.Name)
End If

Next
End Sub[/vbnet]

아래는 안되는 코드
[vbnet]Public Sub LinkTo(ByVal BuildingDB As BuildingLibrary)
‘공간에 대해
For Each myItem As Space In Me.Spaces.Values
If BuildingDB.Spaces.ContainsKey(myItem.Name) Then
myItem = BuildingDB.Spaces(myItem.Name) ‘myItem은 복사본이기에 원본 컬렉션에 영향을 주지 못한다.
End If
Next
End Sub[/vbnet]

‘그래서 수정한 코드 = 되는 코드
[vbnet]Public Sub LinkTo(ByVal BuildingDB As BuildingLibrary)
‘공간에 대해
Dim ItemsToLink As New Spaces

For Each myItem As Space In Me.Spaces.Values
If BuildingDB.Spaces.ContainsKey(myItem.Name) Then
ItemsToLink.Add(myItem.Name, BuildingDB.Spaces(myItem.Name))
End If
Next
Me.Spaces.Clear()
For Each myItem As Space In ItemsToLink.Values
Me.Spaces.Add(myItem.Name, myItem)

Next
For Each myItem As Space In Me.Spaces.Values
CType(myItem, OndolSpace).LinkTo(BuildingDB)
Next
End Sub[/vbnet]

Print Friendly, PDF & Email