Enhancing Looping With Enumerators
Before using enumerators I would have have an exposed data structures and loops like this:
Code:
' Exposed data structures
Public Blocks As New SortedList(Of Integer, Block)
Public RedBlocks As New SortedList(Of Integer, Block)
Public BlueBlocks As New SortedList(Of Integer, Block)
' Loops
For Each blockKVP As KeyValuePair(Of Integer, Block) In Blocks
Dim block As Block = blockKVP.Value
...
Next
For Each blockKVP As KeyValuePair(Of Integer, Block) In BlueBlocks
Dim block As Block = blockKVP.Value
...
Next
Whenever code added/removed blocks to the list the code had to make sure to add/remove from each list. This of course is error prone. Also, if I wanted to maintain another list of blocks in a different color I'd have to modify each block of code that added/removed from the lists.
So I created enumerator classes to encapsulate all this and to protect the data structures. It also made the loop syntax simpler and easier to read.
Code:
' Enumerators
Public Class BlockEnumerator
Implements IEnumerator(Of Block)
...
End Class
Public Class RedBlockEnumator
Implements IEnumerator(Of Block)
....
End Class
Public Class BlockList
Implements IEnumerable(Of Block)
...
End Class
Public Class RedBlockList
Implements IEnumerable(Of Block)
...
End Class
' Protected data structures
Private _Blocks As New SortedList(of integer, Block)
Public Blocks As New BlockList(_Blocks)
Public RedBlocks As New BlockList(_Blocks)
' Simple loops
For Each block In Blocks
...
Next
For Each block In RedBlocks
...
Next
Now my question. I would like to only have one public list and to select the subset of blocks in the looping syntax. I have few thoughts what the syntax might be but I don't know what class/data structures I need in order to do this.
Code Examples
Code:
' Protected data structures
Private _Blocks As New SortedList(of integer, Block)
Public Blocks As New BlockList(_Blocks)
' Loops through all blocks
For Each block In Blocks
...
Next
For Each block In Blocks.AllBlocks
...
Next
For Each block In Blocks(BlockColor.AllColors)
...
Next
' Loops through red blocks
For Each block In Blocks.RedBlocks
...
Next
For Each block In Blocks(BlockColor.RedBlocks)
...
Next
Well, does anyone have any suggestions or know if this is even possible?
Thanks,
Re: Enhancing Looping With Enumerators
I would create a SINGLE class that hadd "All" the blocks, then expose enumerators that only returned the ones which met the requirements.
NO multiple collections to maintain, smaller, faster, less error prone, easier to use....whats not to like?
Re: Enhancing Looping With Enumerators
Quote:
Originally Posted by
Scott.Macmaster
Before using enumerators I would have have an exposed data structures and loops like this:
Code:
' Loops
For Each blockKVP As KeyValuePair(Of Integer, Block) In Blocks
Dim block As Block = blockKVP.Value
...
Next
Whenever code added/removed blocks to the list the code had to make sure to add/remove from each list. This of course is error prone. Also, if I wanted to maintain another list of blocks in a different color I'd have to modify each block of code that added/removed from the lists.
try:
Code:
' Loops
For Each blockKVP As KeyValuePair(Of Integer, Block) In Blocks.Clone
Dim block As Block = blockKVP.Value
...
Next
That way, yo would iterate on each object on the original SortedList, at the cost of duplicating your data structure before the For...Next. You can delete the same objects in the KeyValuePair, without ruining the logic under you For..Each...Next
Re: Enhancing Looping With Enumerators
Clonig the list usually has a bigger performance hit than just using a good pattern for handling addition/deletion. This can be implemented at the collection class level. It is also much easier to make thread safe by localizing all of the locking.
Re: Enhancing Looping With Enumerators
Well, that's what I want to do, have everything in one class. I did some more thinking and found a solution. For some reason it didn't initial occur to me I could have a function in an enumerable class that returns an object of a different enumerable class.
This'll work perfectly for my block example. However, the project I'm actually working on involves the list ordered in different ways so I'll still need to manage multiple lists. However, it'll all be in one class and the enumerable objects returned by the functions in the primary enumerable object won't have add/remove functions so my data structures will be completely protected.
Code:
' Enumerators
Public Class BlocksByIdEnumerator
Implements IEnumerator(Of Block)
...
End Class
Public Class BlocksByNameEnumerator
Implements IEnumerator(Of Student)
...
End Class
' Enumerable classes
Public Class BlocksList
Implements IEnumerable(Of Block)
Private Blocks As New SortedList(of Integer, Block)
Private BlocksByName As New SortedList(of String, Block)
Public Functions ByName() As BlocksByNameList
Return New BlocksByNameList(BlocksByName)
End Function
...
End Class
Public Class BlocksByNameList
Implements IEnumerable(Of Block)
Private Blocks As SortedList(Of String, Block)
...
End Class
' Fully protected data structure
Public blocks As BlocksList
' Looping through blocks
For Each block In blocks
...
Next
' Loop through blocks in a different order
For Each block In blocks.ByName
...
Next
Well, I don't think this can be improved anymore.
Thanks,
Re: Enhancing Looping With Enumerators
Scott, since you posted abbriviated code, I can not be 100% certain, but it still looks as if there is a postential for error.
1) Create BlockList
2) Get Local Reference to BlockList.ByName
3) Remove item from Local Reference (of type BlocksByNameList)
Will the original BlockList properly reflect the change?
Also what happens if the caller tries "new BlocksByNameList" directly?
It seems that this implementation does NOT optimally meet the goal of "Make classes as DIFFICULT as possible to use INCORRECTLY" - Scott Meyers....
Re: Enhancing Looping With Enumerators
I had said, "and the enumerable objects returned by the functions in the primary enumerable object won't have add/remove functions so my data structures will be completely protected"
Without a add/remove functions you can't modify the internal data structure with the local reference returned by BlockList.ByName.
I only have one constructor for BlocksByNameList
Code:
Public Sub New(blocksByName As SortedList(As String, Block))
Blocks = blocksByName
End Sub
So you can't initialize a BlocksByName object manually with the sortedlist inside of Blocks since there isn't a way to get a reference to it. Not that it would matter since it doesn't have add/remove functions. You could initialize it with your own sortedlist but since it doesn't have add/remove functions that would be pointless.
If you have thoughts on how my code could by misused I'd like to know.
Thanks,
Re: Enhancing Looping With Enumerators
Post it all. Attach it as a file if it is too big to paste.
Re: Enhancing Looping With Enumerators
Quote:
Originally Posted by
Scott.Macmaster
I If you have thoughts on how my code could by misused I'd like to know.
I confess that I was looking much more ad the code, than the text. It seems you have most of the major bases covered, with the possible of some unnecessary object lifetime (this could only be confirmed with a fully compilable piece of code that could be carefully analyzed with a proper profiler.