Custom collection and For Each

M

Michael Kellogg

I created a custom collection based on
System.Collections.Specialized.NameObjectCollectionBase. I also
implemented two version of the "Item" property and coded them both as
Default properties.

Now, when I look at the data, everything looks good; the underlying objects
in there, and the Item property returns the same even if I just access like
this: Label(i), so that is cool.

However, I tried to do a For...Each on the object just now and it's not
returning to me the underlying object (as is specified in the Item
properties). Instead it's returning the string key for that element.

What gives? I want to iterate through the collection with a For...Each but
cannot see what I'm doing wrong.

Appreciate any suggestions.
 
C

Cor Ligthert

Michael.

Do you want to know what you are doing wrong in the code you did not show?

You see the code before you, how you think anybody can help you when he does
not know what you did. Therefore when you want help, show some code (piece
by piece the first time and first pasted in a noteback an copied back in
your message to make it readable)

Cor
 
M

Michael Kellogg

Michael.

Do you want to know what you are doing wrong in the code you did not
show?

You see the code before you, how you think anybody can help you when
he does not know what you did. Therefore when you want help, show some
code (piece by piece the first time and first pasted in a noteback an
copied back in your message to make it readable)

Cor

Cor,

My, what a tactful guy you are.

Here is part of the collection of my custom object:
------------

Public Class FormLabels
Inherits System.Collections.Specialized.NameObjectCollectionBase

Default Public ReadOnly Property Item(ByVal index As Integer) As
FormLabel
Get
Return BaseGet(index)
End Get
End Property
Default Public ReadOnly Property Item(ByVal FormCode As String) As
FormLabel
Get
Return BaseGet(FormCode)
End Get
End Property
....
End Class

---------
Here is the code where I try to iterate the collection:
---------
Protected Sub RefreshForms()
With lstForms.Items
.Clear()
Dim fl As FormLabel
Dim fls As FormLabels
fls = m_JobLabel.FormLabels 'pass the copy one time
For Each fl In fls
.Add(fl.FormCode + " (" + fl.FormNumber.ToString + ")")
Next
End With
End Sub

------------
As it stands, I get an InvalidCastException at the "For Each" statement.
I went back and changed fl's definition to "Object" and discovered that
it was handed a String (it is the element's key), not a FormLabel object.
What I don't get is what the "Each" clause goes and gets. I assumed it
was the default property, which should return an object to me, not a
string.

I can work around this by iterating the collection manually, but I want
to know how to get the "Each" to work.



-Michael
 
M

Michael Kellogg

Do if I did not ask to show your code.

I am sorry Michael, without your code I cannot help you.

Cor

?

I just supplied you with all the code in question, as you requested.
Didn't you see all that below my initial comments?



- Michael
 
A

ABad

To handle "For Each" a collection must implement IEnumerable.
NameObjectCollectionBase already implements this interface and it looks like
the implementation iterates over the keys.
 
M

Michael Kellogg

ABad said:
To handle "For Each" a collection must implement IEnumerable.
NameObjectCollectionBase already implements this interface and it
looks like the implementation iterates over the keys.

Let me ask this (I'm not familiar with the interfaces and have not found
any decent info about them, like IEnumerable): Let's say this is what is
happening, that the For Each is enumerating the keys. This makes the
iteration through my collection unusual, because I have to then use the
key that is returned to pull up the actual object inside the collection.
In other words:
----------

dim key as string
for each key in MyObjects
MyObjects(key).myProperty = x
next

----------
Is different than this standard implementation:
----------

dim obj as MyObject
for each obj in MyObjects
obj.myProperty = x
next
 
A

ABad

any decent info about them, like IEnumerable): Let's say this is what is
happening, that the For Each is enumerating the keys.

It is whats happening. I tested it and looked at the IL of the
NameObjectCollectionBase class.
What I'm trying to understand is how to make it work in the latter case.
My Default property is ITEM, which returns an object (not the key
string). What am I missing?

Like I said the "For Each" mechanism is dependent on the IEnumerable
interface, NOT Default property. For NameObjectCollectionBase class, the
implementation is enumerate over the keys. You cannot "elegantly" override
this behavior so you can't depend on NameObjectCollectionBase to do what you
want. Now you could "shadow" the GetEnumerator method and provide your own
implementation of IEnumerator but you should read up on what "shadows" does
before you take this step.

What I would do for an "elegant" design is implement my own class that
implements the ICollection interface. Expose all methods necessary and defer
the implementation details to an existing .NET data structure that supplies
the needed functionality, say hashtable. I would then implement IEnumerable
with my own implementation.

- ABad
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top