By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,830 Members | 1,746 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,830 IT Pros & Developers. It's quick & easy.

Overriding Equals method not being called when doing IndexOf an item in an ArrayList

P: n/a
From reading the documentation, this should be a relatively easy thing. I
have an arraylist of custom class instances which I want to search with
an"indexof" where I'm passing an instance if the class where only the
"searched" property has a value. I expected to get the index into the
arraylist where I could then get the entire class instance. However, the
'indexof' is never calling my overloaded, overrides Equals method. Here is
the code snippet:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim PeopleCollection As New ArrayList

Dim Customer As New Person
Customer.Age = 25
Customer.IsMale = "Yes"

PeopleCollection.Add(Customer)

Dim y As New Person
y.Age = 25
Dim x As Integer = PeopleCollection.IndexOf(y) 'this always
returns -1, meaning it didn't match anything
End Sub

Public Class Person
Private _IsMale As String
Private _age As Integer
Public Overloads Overrides Function equals(ByVal obj As Object) As Boolean
If obj Is Nothing Then Return False
If Me.GetType Is obj.GetType Then
Return Me.Age = CType(obj, Person).Age
End If
End Function
Public Property IsMale() As String
Get
Return _IsMale
End Get
Set(ByVal Value As String)
_IsMale = Value
End Set
End Property
Public Property Age() As Integer
Get
Return _age
End Get
Set(ByVal Value As Integer)
_age = Value
End Set
End Property
End Class

In this example I wanted to get the instance of the PERSON whose age is 25.
If I put a breakpoint in my overloads overrides equals method, it never
breaks. My EQUALS method is not being called.

Can anybody explain what is going on, and how I can get my indexof to do
what I need it to do?

Thanks, John
Nov 21 '05 #1
Share this Question
Share on Google+
18 Replies


P: n/a

JohnR wrote:
From reading the documentation, this should be a relatively easy thing. I have an arraylist of custom class instances which I want to search with an"indexof" where I'm passing an instance if the class where only the "searched" property has a value. I expected to get the index into the arraylist where I could then get the entire class instance. However, the 'indexof' is never calling my overloaded, overrides Equals method. Here is the code snippet:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim PeopleCollection As New ArrayList

Dim Customer As New Person
Customer.Age = 25
Customer.IsMale = "Yes"

PeopleCollection.Add(Customer)

Dim y As New Person
y.Age = 25
Dim x As Integer = PeopleCollection.IndexOf(y) 'this always
returns -1, meaning it didn't match anything
End Sub

Public Class Person
Private _IsMale As String
Private _age As Integer
Public Overloads Overrides Function equals(ByVal obj As Object) As Boolean If obj Is Nothing Then Return False
If Me.GetType Is obj.GetType Then
Return Me.Age = CType(obj, Person).Age
End If
End Function [snip]
In this example I wanted to get the instance of the PERSON whose age is 25. If I put a breakpoint in my overloads overrides equals method, it never breaks. My EQUALS method is not being called.

Can anybody explain what is going on, and how I can get my indexof to do what I need it to do?


This is technically a feature not a bug (doesn't help I know), as the
behaviour is as documented. In the docs for ArrayList.IndexOf, you will
see it says:
Remarks
....
This method determines equality by calling Object.Equals.


which is why your class's Equals method is not being called. To get the
behaviour you want you have a number of choices which include these as
I think the most obvious two:

- Implement a strongly-typed ArrayList for storing solely Person
objects, that uses Person.Equals when doing an IndexOf operation;

- Use a different collection class, one that explicitly supports the
use of overriden Equals operators. For example, a Hashtable uses the
Equals implementation of the key objects, rather than always using
Object.Equals

If you need wither or both of these options explained more, feel free
to ask :)

--
Larry Lard
Replies to group please

Nov 21 '05 #2

P: n/a
Hi Larry,
- Implement a strongly-typed ArrayList for storing solely Person objects, that uses Person.Equals when doing an IndexOf operation;

I'm not exactly sure what you mean...

Every entry into the arraylist was of type PERSON. But, still, the indexof
didn't call the object.equals in the Person class. I'm guessing that it is
calling a object.equals method that is in the ArrayList class, so I tried
to create a new class ARRAYLISTPERSON which inherits from arraylist. I then
put the overrides overloads function equals(byval obj as object) as boolean
in the arraylistperson class def'n and stored my PERSON instances in this
class rather than the regular arraylist class. Unfortunately, when the
indexof method was called, my Equals function was not called, so I'm still
at a loss.

Do you have a small code example of how to override the Object.equals
method of an arraylist.indexof?

Thanks, John
"Larry Lard" <la*******@hotmail.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com...
JohnR wrote:
From reading the documentation, this should be a relatively easy

thing. I
have an arraylist of custom class instances which I want to search

with
an"indexof" where I'm passing an instance if the class where only the

"searched" property has a value. I expected to get the index into

the
arraylist where I could then get the entire class instance.

However, the
'indexof' is never calling my overloaded, overrides Equals method.

Here is
the code snippet:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim PeopleCollection As New ArrayList

Dim Customer As New Person
Customer.Age = 25
Customer.IsMale = "Yes"

PeopleCollection.Add(Customer)

Dim y As New Person
y.Age = 25
Dim x As Integer = PeopleCollection.IndexOf(y) 'this always
returns -1, meaning it didn't match anything
End Sub

Public Class Person
Private _IsMale As String
Private _age As Integer
Public Overloads Overrides Function equals(ByVal obj As Object) As

Boolean
If obj Is Nothing Then Return False
If Me.GetType Is obj.GetType Then
Return Me.Age = CType(obj, Person).Age
End If
End Function

[snip]

In this example I wanted to get the instance of the PERSON whose age

is 25.
If I put a breakpoint in my overloads overrides equals method, it

never
breaks. My EQUALS method is not being called.

Can anybody explain what is going on, and how I can get my indexof to

do
what I need it to do?


This is technically a feature not a bug (doesn't help I know), as the
behaviour is as documented. In the docs for ArrayList.IndexOf, you will
see it says:
Remarks
...
This method determines equality by calling Object.Equals.


which is why your class's Equals method is not being called. To get the
behaviour you want you have a number of choices which include these as
I think the most obvious two:

- Implement a strongly-typed ArrayList for storing solely Person
objects, that uses Person.Equals when doing an IndexOf operation;

- Use a different collection class, one that explicitly supports the
use of overriden Equals operators. For example, a Hashtable uses the
Equals implementation of the key objects, rather than always using
Object.Equals

If you need wither or both of these options explained more, feel free
to ask :)

--
Larry Lard
Replies to group please

Nov 21 '05 #3

P: n/a

JohnR wrote:
Hi Larry,
> - Implement a strongly-typed ArrayList for storing solely
Person
> objects, that uses Person.Equals when doing an
IndexOf operation;

I'm not exactly sure what you mean...

Every entry into the arraylist was of type PERSON. But, still, the indexof didn't call the object.equals in the Person class. I'm guessing that it is calling a object.equals method that is in the ArrayList class,
An ArrayList will *always* use Object.Equals (the Equals method defined
in the base class Object) when checking for equality in its IndexOf
method. That is just the way ArrayList is implemented.

so I tried
to create a new class ARRAYLISTPERSON which inherits from arraylist. I then put the overrides overloads function equals(byval obj as object) as boolean in the arraylistperson class def'n and stored my PERSON instances in this class rather than the regular arraylist class. Unfortunately, when the indexof method was called, my Equals function was not called, so I'm still at a loss.
Supplying a new Equals method, wherever you do it, won't change
ArrayList's behaviour - it will always use Object.Equals.

Do you have a small code example of how to override the Object.equals method of an arraylist.indexof?
What you need to change the behaviour of is the *IndexOf* method. Here
is the general idea:

Public Class ArrayListOfPerson
Inherits ArrayList

Public Shadows Function IndexOf(ByVal p As Person) As Integer
Dim iterp As Person
Dim i As Integer

For i = 0 To Me.Count - 1
iterp = DirectCast(Me(i), Person)
If p.Equals(iterp) Then Return i
Next

Return -1
End Function
End Class

Usage example:

Dim al As ArrayList = New ArrayList

al.Add(New Person(10))
al.Add(New Person(5))

MsgBox(al.IndexOf(New Person(5)))
'this will show -1, because ArrayList uses Object.Equals to
compare
'while performing the IndexOf method
'and Object.Equals requires reference equivalence

Dim alp As ArrayListOfPerson = New ArrayListOfPerson

alp.Add(New Person(10))
alp.Add(New Person(5))

MsgBox(alp.IndexOf(New Person(5)))
'this will return 1, because ArrayListOfPerson uses
Person.Equals
'while performing IndexOf(As Person)
**** PLEASE NOTE **** that this lacks robustness in a number of ways,
and this is *not* how I would suggest implementing a strongly-typed
collection in anything larger than a toy (ie personal-use only)
application. The main problems are that: There is nothing to stop a
careless client of ArrayListOfPerson adding a non-Person; the Item()
property is still returned As Object so must be casted to Person; an
ArrayListOfPerson can be casted down to ArrayList and lose all its
custom behaviour. To reiterate, DON'T do custom collections in this way
in seroius apps! This is just an example! You can find many posts on
the correct ways to implement custom collections here in this group. Or
start a new thread and ask, as that is a separate topic :)

Thanks, John
"Larry Lard" <la*******@hotmail.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com...

JohnR wrote:
From reading the documentation, this should be a relatively easy

thing. I
have an arraylist of custom class instances which I want to search

with
an"indexof" where I'm passing an instance if the class where only the
"searched" property has a value. I expected to get the index into

the
arraylist where I could then get the entire class instance.

However, the
'indexof' is never calling my overloaded, overrides Equals method.

Here is
the code snippet:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim PeopleCollection As New ArrayList

Dim Customer As New Person
Customer.Age = 25
Customer.IsMale = "Yes"

PeopleCollection.Add(Customer)

Dim y As New Person
y.Age = 25
Dim x As Integer = PeopleCollection.IndexOf(y) 'this
always returns -1, meaning it didn't match anything
End Sub

Public Class Person
Private _IsMale As String
Private _age As Integer
Public Overloads Overrides Function equals(ByVal obj As Object) As

Boolean
If obj Is Nothing Then Return False
If Me.GetType Is obj.GetType Then
Return Me.Age = CType(obj, Person).Age
End If
End Function

[snip]

In this example I wanted to get the instance of the PERSON whose

age is 25.
If I put a breakpoint in my overloads overrides equals method, it

never
breaks. My EQUALS method is not being called.

Can anybody explain what is going on, and how I can get my indexof
to do
what I need it to do?


This is technically a feature not a bug (doesn't help I know), as the behaviour is as documented. In the docs for ArrayList.IndexOf, you will see it says:

Remarks
...
This method determines equality by calling Object.Equals.


which is why your class's Equals method is not being called. To get the behaviour you want you have a number of choices which include these as I think the most obvious two:

- Implement a strongly-typed ArrayList for storing solely Person
objects, that uses Person.Equals when doing an IndexOf operation;

- Use a different collection class, one that explicitly supports the use of overriden Equals operators. For example, a Hashtable uses the Equals implementation of the key objects, rather than always using
Object.Equals

If you need wither or both of these options explained more, feel free to ask :)

--
Larry Lard
Replies to group please


Nov 21 '05 #4

P: n/a
Hi Larry,

thanks for the quick reply. You have confirmed my idea of what needs to
be done... I have created my own custom arraylist as you suggested, and
created a few 'wrapper' functions to store/access/search/retrieve items
stored in it regardless of class.

it is a shame, however, that the arraylist.indexof class doesn't call the
overridden object.equals methods. Oh, well...

Regards,
John

"Larry Lard" <la*******@hotmail.com> wrote in message
news:11**********************@z14g2000cwz.googlegr oups.com...

JohnR wrote:
Hi Larry,
> - Implement a strongly-typed ArrayList for storing solely
Person
> objects, that uses Person.Equals when doing an

IndexOf
operation;

I'm not exactly sure what you mean...

Every entry into the arraylist was of type PERSON. But, still, the

indexof
didn't call the object.equals in the Person class. I'm guessing that

it is
calling a object.equals method that is in the ArrayList class,


An ArrayList will *always* use Object.Equals (the Equals method defined
in the base class Object) when checking for equality in its IndexOf
method. That is just the way ArrayList is implemented.

so I tried
to create a new class ARRAYLISTPERSON which inherits from arraylist.

I then
put the overrides overloads function equals(byval obj as object) as

boolean
in the arraylistperson class def'n and stored my PERSON instances in

this
class rather than the regular arraylist class. Unfortunately, when

the
indexof method was called, my Equals function was not called, so I'm

still
at a loss.


Supplying a new Equals method, wherever you do it, won't change
ArrayList's behaviour - it will always use Object.Equals.

Do you have a small code example of how to override the

Object.equals
method of an arraylist.indexof?


What you need to change the behaviour of is the *IndexOf* method. Here
is the general idea:

Public Class ArrayListOfPerson
Inherits ArrayList

Public Shadows Function IndexOf(ByVal p As Person) As Integer
Dim iterp As Person
Dim i As Integer

For i = 0 To Me.Count - 1
iterp = DirectCast(Me(i), Person)
If p.Equals(iterp) Then Return i
Next

Return -1
End Function
End Class

Usage example:

Dim al As ArrayList = New ArrayList

al.Add(New Person(10))
al.Add(New Person(5))

MsgBox(al.IndexOf(New Person(5)))
'this will show -1, because ArrayList uses Object.Equals to
compare
'while performing the IndexOf method
'and Object.Equals requires reference equivalence

Dim alp As ArrayListOfPerson = New ArrayListOfPerson

alp.Add(New Person(10))
alp.Add(New Person(5))

MsgBox(alp.IndexOf(New Person(5)))
'this will return 1, because ArrayListOfPerson uses
Person.Equals
'while performing IndexOf(As Person)
**** PLEASE NOTE **** that this lacks robustness in a number of ways,
and this is *not* how I would suggest implementing a strongly-typed
collection in anything larger than a toy (ie personal-use only)
application. The main problems are that: There is nothing to stop a
careless client of ArrayListOfPerson adding a non-Person; the Item()
property is still returned As Object so must be casted to Person; an
ArrayListOfPerson can be casted down to ArrayList and lose all its
custom behaviour. To reiterate, DON'T do custom collections in this way
in seroius apps! This is just an example! You can find many posts on
the correct ways to implement custom collections here in this group. Or
start a new thread and ask, as that is a separate topic :)

Thanks, John
"Larry Lard" <la*******@hotmail.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com...
>
> JohnR wrote:
>> From reading the documentation, this should be a relatively easy
> thing. I
>> have an arraylist of custom class instances which I want to search
> with
>> an"indexof" where I'm passing an instance if the class where only

the >
>> "searched" property has a value. I expected to get the index into
> the
>> arraylist where I could then get the entire class instance.
> However, the
>> 'indexof' is never calling my overloaded, overrides Equals method.
> Here is
>> the code snippet:
>>
>> Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
>> System.EventArgs) Handles MyBase.Load
>>
>> Dim PeopleCollection As New ArrayList
>>
>> Dim Customer As New Person
>> Customer.Age = 25
>> Customer.IsMale = "Yes"
>>
>> PeopleCollection.Add(Customer)
>>
>> Dim y As New Person
>> y.Age = 25
>> Dim x As Integer = PeopleCollection.IndexOf(y) 'this always >> returns -1, meaning it didn't match anything
>> End Sub
>>
>> Public Class Person
>> Private _IsMale As String
>> Private _age As Integer
>> Public Overloads Overrides Function equals(ByVal obj As Object) As
> Boolean
>> If obj Is Nothing Then Return False
>> If Me.GetType Is obj.GetType Then
>> Return Me.Age = CType(obj, Person).Age
>> End If
>> End Function
> [snip]
>>
>> In this example I wanted to get the instance of the PERSON whose age > is 25.
>> If I put a breakpoint in my overloads overrides equals method, it
> never
>> breaks. My EQUALS method is not being called.
>>
>> Can anybody explain what is going on, and how I can get my indexof to > do
>> what I need it to do?
>
> This is technically a feature not a bug (doesn't help I know), as the > behaviour is as documented. In the docs for ArrayList.IndexOf, you will > see it says:
>
>>>
> Remarks
> ...
> This method determines equality by calling Object.Equals.
>>>
>
> which is why your class's Equals method is not being called. To get the > behaviour you want you have a number of choices which include these as > I think the most obvious two:
>
> - Implement a strongly-typed ArrayList for storing solely Person
> objects, that uses Person.Equals when doing an IndexOf operation;
>
> - Use a different collection class, one that explicitly supports the > use of overriden Equals operators. For example, a Hashtable uses the > Equals implementation of the key objects, rather than always using
> Object.Equals
>
> If you need wither or both of these options explained more, feel free > to ask :)
>
> --
> Larry Lard
> Replies to group please
>

Nov 21 '05 #5

P: n/a
John,
Your code works as expected! As Larry pointed out, ArrayList.IndexOf uses
Object.Equals to match the items. Object.Equals is an overridable method, so
it behaves polymorphically across any type that overrides it. Your Person
type overrides Object.Equals. So ArrayList.IndexOf will call Person.Equals.

Trying your code as posted returns 0 in VB.NET 2003!

To see that Person.Equals is actually getting called, simply place a
breakpoint on the Person.Equals method before calling
PeopleCollection.IndexOf.

Hope this helps
Jay
"JohnR" <Jo******@hotmail.com> wrote in message
news:HRkbe.5251$WX.1041@trndny01...
| From reading the documentation, this should be a relatively easy thing.
I
| have an arraylist of custom class instances which I want to search with
| an"indexof" where I'm passing an instance if the class where only the
| "searched" property has a value. I expected to get the index into the
| arraylist where I could then get the entire class instance. However, the
| 'indexof' is never calling my overloaded, overrides Equals method. Here
is
| the code snippet:
|
| Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
| System.EventArgs) Handles MyBase.Load
|
| Dim PeopleCollection As New ArrayList
|
| Dim Customer As New Person
| Customer.Age = 25
| Customer.IsMale = "Yes"
|
| PeopleCollection.Add(Customer)
|
| Dim y As New Person
| y.Age = 25
| Dim x As Integer = PeopleCollection.IndexOf(y) 'this always
| returns -1, meaning it didn't match anything
| End Sub
|
| Public Class Person
| Private _IsMale As String
| Private _age As Integer
| Public Overloads Overrides Function equals(ByVal obj As Object) As Boolean
| If obj Is Nothing Then Return False
| If Me.GetType Is obj.GetType Then
| Return Me.Age = CType(obj, Person).Age
| End If
| End Function
| Public Property IsMale() As String
| Get
| Return _IsMale
| End Get
| Set(ByVal Value As String)
| _IsMale = Value
| End Set
| End Property
| Public Property Age() As Integer
| Get
| Return _age
| End Get
| Set(ByVal Value As Integer)
| _age = Value
| End Set
| End Property
| End Class
|
| In this example I wanted to get the instance of the PERSON whose age is
25.
| If I put a breakpoint in my overloads overrides equals method, it never
| breaks. My EQUALS method is not being called.
|
| Can anybody explain what is going on, and how I can get my indexof to do
| what I need it to do?
|
| Thanks, John
|
|
Nov 21 '05 #6

P: n/a
Larry,
| >>
| Remarks
| ...
| This method determines equality by calling Object.Equals.
| >>
|
| which is why your class's Equals method is not being called. To get the
| behaviour you want you have a number of choices which include these as
Err! Object.Equals is overridable, John overrode it. Overridable means the
method behaves polymorphically.

When ArrayList.IndexOf calls Object.Equals, because John's Person.Equals
overrides it, Person.Equals will actually be called!

Using Shadows is anti-polymorphic. When ArrayList.IndexOf calls
Object.Equals, if Person shadows Equals, then Object.Equals will be called &
not Person.Equals. Rarely do you want to use Shadows as they are
anti-polymorphic!

John's code as posted works as expected, I suspect there is another problem
going on.

Hope this helps
Jay


"Larry Lard" <la*******@hotmail.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com...
|
| JohnR wrote:
| > From reading the documentation, this should be a relatively easy
| thing. I
| > have an arraylist of custom class instances which I want to search
| with
| > an"indexof" where I'm passing an instance if the class where only the
|
| > "searched" property has a value. I expected to get the index into
| the
| > arraylist where I could then get the entire class instance.
| However, the
| > 'indexof' is never calling my overloaded, overrides Equals method.
| Here is
| > the code snippet:
| >
| > Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
| > System.EventArgs) Handles MyBase.Load
| >
| > Dim PeopleCollection As New ArrayList
| >
| > Dim Customer As New Person
| > Customer.Age = 25
| > Customer.IsMale = "Yes"
| >
| > PeopleCollection.Add(Customer)
| >
| > Dim y As New Person
| > y.Age = 25
| > Dim x As Integer = PeopleCollection.IndexOf(y) 'this always
| > returns -1, meaning it didn't match anything
| > End Sub
| >
| > Public Class Person
| > Private _IsMale As String
| > Private _age As Integer
| > Public Overloads Overrides Function equals(ByVal obj As Object) As
| Boolean
| > If obj Is Nothing Then Return False
| > If Me.GetType Is obj.GetType Then
| > Return Me.Age = CType(obj, Person).Age
| > End If
| > End Function
| [snip]
| >
| > In this example I wanted to get the instance of the PERSON whose age
| is 25.
| > If I put a breakpoint in my overloads overrides equals method, it
| never
| > breaks. My EQUALS method is not being called.
| >
| > Can anybody explain what is going on, and how I can get my indexof to
| do
| > what I need it to do?
|
| This is technically a feature not a bug (doesn't help I know), as the
| behaviour is as documented. In the docs for ArrayList.IndexOf, you will
| see it says:
|
| >>
| Remarks
| ...
| This method determines equality by calling Object.Equals.
| >>
|
| which is why your class's Equals method is not being called. To get the
| behaviour you want you have a number of choices which include these as
| I think the most obvious two:
|
| - Implement a strongly-typed ArrayList for storing solely Person
| objects, that uses Person.Equals when doing an IndexOf operation;
|
| - Use a different collection class, one that explicitly supports the
| use of overriden Equals operators. For example, a Hashtable uses the
| Equals implementation of the key objects, rather than always using
| Object.Equals
|
| If you need wither or both of these options explained more, feel free
| to ask :)
|
| --
| Larry Lard
| Replies to group please
|
Nov 21 '05 #7

P: n/a

Jay B. Harlow [MVP - Outlook] wrote:
Larry,
| >>
| Remarks
| ...
| This method determines equality by calling Object.Equals.
| >>
|
| which is why your class's Equals method is not being called. To get the | behaviour you want you have a number of choices which include these as Err! Object.Equals is overridable, John overrode it. Overridable means the method behaves polymorphically.

When ArrayList.IndexOf calls Object.Equals, because John's Person.Equals overrides it, Person.Equals will actually be called!

Using Shadows is anti-polymorphic. When ArrayList.IndexOf calls
Object.Equals, if Person shadows Equals, then Object.Equals will be called & not Person.Equals. Rarely do you want to use Shadows as they are
anti-polymorphic!

John's code as posted works as expected, I suspect there is another problem going on.


So it does. Guess I should have checked that before going off on one,
to avoid looking silly now. Oh well.

--
Larry Lard
Replies to group please

Nov 21 '05 #8

P: n/a
In article <HRkbe.5251$WX.1041@trndny01>, JohnR wrote:
From reading the documentation, this should be a relatively easy thing. I
have an arraylist of custom class instances which I want to search with
an"indexof" where I'm passing an instance if the class where only the
"searched" property has a value. I expected to get the index into the
arraylist where I could then get the entire class instance. However, the
'indexof' is never calling my overloaded, overrides Equals method. Here is
the code snippet:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim PeopleCollection As New ArrayList

Dim Customer As New Person
Customer.Age = 25
Customer.IsMale = "Yes"

PeopleCollection.Add(Customer)

Dim y As New Person
y.Age = 25
Dim x As Integer = PeopleCollection.IndexOf(y) 'this always
returns -1, meaning it didn't match anything
End Sub

Public Class Person
Private _IsMale As String
Private _age As Integer
Public Overloads Overrides Function equals(ByVal obj As Object) As Boolean
If obj Is Nothing Then Return False
If Me.GetType Is obj.GetType Then
Return Me.Age = CType(obj, Person).Age
End If
End Function
Public Property IsMale() As String
Get
Return _IsMale
End Get
Set(ByVal Value As String)
_IsMale = Value
End Set
End Property
Public Property Age() As Integer
Get
Return _age
End Get
Set(ByVal Value As Integer)
_age = Value
End Set
End Property
End Class

In this example I wanted to get the instance of the PERSON whose age is 25.
If I put a breakpoint in my overloads overrides equals method, it never
breaks. My EQUALS method is not being called.

Can anybody explain what is going on, and how I can get my indexof to do
what I need it to do?

Thanks, John


IMHO, this is a bug... The problem is that it seems that the arraylist
Index of operator does something like the following (obviously aircode):

For Each obj As Object in List
value.Equals (obj)
Next

Which is backwards from what you would expect:

For Each obj As Object in List
obj.Equals (value)
Next

So, to get around this you need create a custom collection class that
overrides IndexOf... Here is my C# implementation of a class I did:

public int IndexOf(string value)
{
int index = -1;

// HACK: Get around strange arraylist.indexof method implementation...
for (int i = 0; i < this.InnerList.Count; i++)
{
if (this.InnerList[i].Equals(value))
{
index = i;
break;
}
}

return index;
}

The funny thing is that Mono did it the right way... But, broke it to
be like .NET in response to a post I made on the mono mailing list :)

--
Tom Shelton [MVP]
Nov 21 '05 #9

P: n/a
Tom,
| IMHO, this is a bug... The problem is that it seems that the arraylist
| Index of operator does something like the following (obviously aircode):

I don't see there is a Bug in John's code. If you try his code it works as
expected in VS.NET 2003 (.NET 1.1)!
| For Each obj As Object in List
| value.Equals (obj)
| Next
|
| Which is backwards from what you would expect:
|
| For Each obj As Object in List
| obj.Equals (value)
| Next

Object.Equals is defined such that "if x.Equals(y) return the same value as
y.Equals(x)" so I don't really see a problem or bug in your sample either!

http://msdn.microsoft.com/library/de...ualstopic1.asp

Hope this helps
Jay


"Tom Shelton" <to*@YOUKNOWTHEDRILLmtogden.com> wrote in message
news:uz**************@TK2MSFTNGP14.phx.gbl...
| In article <HRkbe.5251$WX.1041@trndny01>, JohnR wrote:
| > From reading the documentation, this should be a relatively easy thing.
I
| > have an arraylist of custom class instances which I want to search with
| > an"indexof" where I'm passing an instance if the class where only the
| > "searched" property has a value. I expected to get the index into the
| > arraylist where I could then get the entire class instance. However,
the
| > 'indexof' is never calling my overloaded, overrides Equals method. Here
is
| > the code snippet:
| >
| > Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
| > System.EventArgs) Handles MyBase.Load
| >
| > Dim PeopleCollection As New ArrayList
| >
| > Dim Customer As New Person
| > Customer.Age = 25
| > Customer.IsMale = "Yes"
| >
| > PeopleCollection.Add(Customer)
| >
| > Dim y As New Person
| > y.Age = 25
| > Dim x As Integer = PeopleCollection.IndexOf(y) 'this always
| > returns -1, meaning it didn't match anything
| > End Sub
| >
| > Public Class Person
| > Private _IsMale As String
| > Private _age As Integer
| > Public Overloads Overrides Function equals(ByVal obj As Object) As
Boolean
| > If obj Is Nothing Then Return False
| > If Me.GetType Is obj.GetType Then
| > Return Me.Age = CType(obj, Person).Age
| > End If
| > End Function
| > Public Property IsMale() As String
| > Get
| > Return _IsMale
| > End Get
| > Set(ByVal Value As String)
| > _IsMale = Value
| > End Set
| > End Property
| > Public Property Age() As Integer
| > Get
| > Return _age
| > End Get
| > Set(ByVal Value As Integer)
| > _age = Value
| > End Set
| > End Property
| > End Class
| >
| > In this example I wanted to get the instance of the PERSON whose age is
25.
| > If I put a breakpoint in my overloads overrides equals method, it never
| > breaks. My EQUALS method is not being called.
| >
| > Can anybody explain what is going on, and how I can get my indexof to do
| > what I need it to do?
| >
| > Thanks, John
| >
| >
|
| IMHO, this is a bug... The problem is that it seems that the arraylist
| Index of operator does something like the following (obviously aircode):
|
| For Each obj As Object in List
| value.Equals (obj)
| Next
|
| Which is backwards from what you would expect:
|
| For Each obj As Object in List
| obj.Equals (value)
| Next
|
| So, to get around this you need create a custom collection class that
| overrides IndexOf... Here is my C# implementation of a class I did:
|
| public int IndexOf(string value)
| {
| int index = -1;
|
| // HACK: Get around strange arraylist.indexof method implementation...
| for (int i = 0; i < this.InnerList.Count; i++)
| {
| if (this.InnerList[i].Equals(value))
| {
| index = i;
| break;
| }
| }
|
| return index;
| }
|
| The funny thing is that Mono did it the right way... But, broke it to
| be like .NET in response to a post I made on the mono mailing list :)
|
| --
| Tom Shelton [MVP]
Nov 21 '05 #10

P: n/a
In article <O5**************@TK2MSFTNGP09.phx.gbl>, Jay B. Harlow [MVP - Outlook] wrote:
Tom,
| I see that... I never noticed it, but that seems to be rather strange.
| I have a class that I can compare to a string, but is not a string. So,
| I want to overload equals to handle that case. But, then that
| breaks that condition because:
My understanding is that Object.Equals should only succeed if both types are
identical or at least derived types. The Point example on the link I gave
earlier demonstrates this "rule", however I don't see the "rule" spelled
out...

I would not expect Person.Equals(String) to succeed.

| So, really my implementation of equals wasn't to the spec. I don't like
| that, condition. I did it that way because it simplified a lot of code I
had to
| write in the UI to manipulate those objects, so I don't think I'll change
it
| now.
I would consider putting a TODO or HACK comment, so anyone inheriting your
code knows you meant to do that...

Here is another link on implementing Equals:

http://msdn.microsoft.com/library/de...pconEquals.asp

Alternatively I would consider adding an overloaded Equals method that
accepts a String, that does the String comparison & leave the Equals(Object)
method alone.

I like the idea about the overloaded string version... I it would be a
very simple modification to my code, and the result would be the same.

--
Tom Shelton [MVP]
Nov 21 '05 #11

P: n/a
OK, first I want to thank all that contributed to this conversation. after
much experimenting I have (I think) narrowed down what is going on
concerning the ARRAYLIST.INDEXOF functionality.

1) in a normal arraylist containing custom class instances, if you pass an
instance of that custom class to the indexof method, it all works as
expected.

Example: x = arraylist.indexof(mycustomclass)

Indeed, the overridden object.equals method in your custom class is called
as verified by a breakpoint in the code.

2) If you pass anything other than an instance of your custom class to the
indexof method (even if your object.equals code would know how to handle it)
the indexof method will always return -1 (not found).

Example: x = arraylist.indexof(integer) will always return -1

I'm guessing that the standard indexof method initially checks the type of
the parameter and if it's not the same as the type contained in the
arraylist it chooses not to continue by calling object.equals. it just
gives up and returns a -1. The standard indexof method knows that the
standard object.equals method expects an instance of the 'myclass' class and
does not allow for the possibility that you have overridden the
object.equals method with a more intelligent one.

So what do you do if you have coded some intelligent object.equals methods
and want to take advantage of them?

Example: indexof(myclass) or indexof("string") or indexof(integer)
could all

work because my object.equals method tests for the 'typeof'
parameter passed

and would handle each case appropriately.

What you need to do is create a custom Arraylist class (ie: MyArraylist)
which inherits Arraylist and overrides the indexof method as follows:

Public Class MyArraylist

Inherits ArrayList

Public Overloads Overrides Function indexof(ByVal obj As Object) As
Integer

If Me.Count = 0 Then Return -1

For i As Integer = 0 To Me.Count - 1

If Me.Item(i).Equals(obj) Then

Return i

End If

Next

Return -1

End Function

End Class

This overridden indexof method does not care about the type of the parameter
passed to it. As long as the arraylist is not empty (me.count >0) it will
call the object.equals method and you will get the results you expect.
Using this custom arraylist for your collection of objects gives you a
tremendous amount of flexibility and greatly simplifies application code
that you need to grab a particular class instance out of the arraylist,
since you can "identify" the class instance you want by as many ways you can
think of (as long as they are properly handled in you custom object.equals
method!).

Anyway, that's it. The above is based on my experimentation and works fine
for me... I hope this will help anybody else that is having issues with the
arraylist.indexof functionality.

John


Nov 21 '05 #12

P: n/a
John,
| 2) If you pass anything other than an instance of your custom class to the
| indexof method (even if your object.equals code would know how to handle
it)
| the indexof method will always return -1 (not found).
As I told Tom: I would expect that! As my understanding is that
Object.Equals should only succeed if both types are identical or at least
derived types. The Point example on the link I gave earlier demonstrates
this "rule", however I don't see the "rule" spelled out...

Even with Derived types there is risk involved will allowing the
comparison...

| So what do you do if you have coded some intelligent object.equals methods
| and want to take advantage of them?
Unfortunately your "intelligent object.equals", now is comparing apples to
auto parts. Comparing apples to auto parts is not really logical
("intelligent"). I can see comparing an Apple to an Orange, as they are both
fruits. However! An Apple cannot be an Orange, only attributes of the Apple
can be the same as attributes of the Orange, ergo you should be comparing
the attributes of the Apple & Orange instead of attempting to compare the
Apple & Orange directly!

| Anyway, that's it. The above is based on my experimentation and works fine
| for me... I hope this will help anybody else that is having issues with
the
| arraylist.indexof functionality.
ArrayList.IndexOf seems to work as I would expect it to! As I showed in my
sample earlier I don't allow my Object.Equals to compare objects of
different types, (Person <> String). If I needed to search the ArrayList for
an object with a specific attribute I would define an alternate IndexOf
(with a specific name) that did the look up.
Public Function SearchForFirstName(name As String) As Integer
For i As Integer = 0 To Me.Count - 1
If Me.Item(i).FirstName = name Then
Return index
End If
Next
Return -1
End Function

As its obvious that SearchForFirstName is searching for an object with a
specific first name.

If the object supported implicit or explicit conversion between types
(current C# or VB.NET 2005 overloaded Widening or Narrowing CType
operators), such as a String can be widened to a Categoryobject. I would do
this conversion before calling the IndexOf operator. Although there is a
conversion between String & Category, Category.Equals would still only
compare two Category values.

Hope this helps
Jay
"JohnR" <Jo******@hotmail.com> wrote in message
news:Lq7ce.2139$pc7.327@trndny05...
| OK, first I want to thank all that contributed to this conversation.
after
| much experimenting I have (I think) narrowed down what is going on
| concerning the ARRAYLIST.INDEXOF functionality.
|
|
|
| 1) in a normal arraylist containing custom class instances, if you pass an
| instance of that custom class to the indexof method, it all works as
| expected.
|
| Example: x = arraylist.indexof(mycustomclass)
|
| Indeed, the overridden object.equals method in your custom class is called
| as verified by a breakpoint in the code.
|
|
|
| 2) If you pass anything other than an instance of your custom class to the
| indexof method (even if your object.equals code would know how to handle
it)
| the indexof method will always return -1 (not found).
|
|
|
| Example: x = arraylist.indexof(integer) will always return -1
|
|
|
| I'm guessing that the standard indexof method initially checks the type of
| the parameter and if it's not the same as the type contained in the
| arraylist it chooses not to continue by calling object.equals. it just
| gives up and returns a -1. The standard indexof method knows that the
| standard object.equals method expects an instance of the 'myclass' class
and
| does not allow for the possibility that you have overridden the
| object.equals method with a more intelligent one.
|
|
|
| So what do you do if you have coded some intelligent object.equals methods
| and want to take advantage of them?
|
| Example: indexof(myclass) or indexof("string") or indexof(integer)
| could all
|
| work because my object.equals method tests for the 'typeof'
| parameter passed
|
| and would handle each case appropriately.
|
|
|
| What you need to do is create a custom Arraylist class (ie: MyArraylist)
| which inherits Arraylist and overrides the indexof method as follows:
|
|
|
| Public Class MyArraylist
|
| Inherits ArrayList
|
| Public Overloads Overrides Function indexof(ByVal obj As Object) As
| Integer
|
| If Me.Count = 0 Then Return -1
|
| For i As Integer = 0 To Me.Count - 1
|
| If Me.Item(i).Equals(obj) Then
|
| Return i
|
| End If
|
| Next
|
| Return -1
|
| End Function
|
| End Class
|
|
|
| This overridden indexof method does not care about the type of the
parameter
| passed to it. As long as the arraylist is not empty (me.count >0) it will
| call the object.equals method and you will get the results you expect.
| Using this custom arraylist for your collection of objects gives you a
| tremendous amount of flexibility and greatly simplifies application code
| that you need to grab a particular class instance out of the arraylist,
| since you can "identify" the class instance you want by as many ways you
can
| think of (as long as they are properly handled in you custom object.equals
| method!).
|
|
|
| Anyway, that's it. The above is based on my experimentation and works fine
| for me... I hope this will help anybody else that is having issues with
the
| arraylist.indexof functionality.
|
|
|
| John
|
|
|
|
|
|
|
|
Nov 21 '05 #13

P: n/a
Hi Jay,

I can appreciate your point of view... there are some good reasons to
limit indexof to an apples to apples comparison. However, I'd like to make
my case as to why is can be valuable to have a more intelligent
comparison.... and it's much more logical than, as you said, "comparing
apples to auto parts". (now, why would anybody want to do that??)

In our commercial application we have (so far) about 40 different custom
classes which define the specific things the system will deal with. For now
lets say we have an Employee class, a Job category class, and an Employee
Rating class.
In our actual application virtually everything that is a custom class is
stored in an arraylist so that it can be expanded at any time. In my
example it means that you can start off with 15 job categories, and add 25
more at a later date, without having to change 1 line of code. In some
classes we set up an ENUM for ease and clarity of coding, and some ENUMs
have 80 to 90 entries. To make matters more interesting, it is very common
that a class has a property that is another custom class. In the example
you could imagine that an instance of the Employee class has a property that
is an instance of the JobCategory class.
So the question (and it is a very serious question) is this: how can we
easily code a retrieval process that will retrieve a specific instance of a
custom class that is stored in one of the arraylists.
In different situations we may have different 'bits' of information to
identify the instance we want. For example, we might want to search for a
Job Category of "17" (that's it's unique job code) OR we may want to search
for a Job Category of "Teacher" (that's it's unique name). Either one is
enough to uniquely identify the instance of the JobCategory class we are
interested in. Now take this simple example and multiply it 100 fold and
you begin to see why having a separate indexof for each possible way we want
to search would quickly get out of control.
The solution we are using involves a derived arraylist that has overridden
the indexof method. All of our class instances are stored in these custom
arraylists. The indexof method will call the object.equals method as long
as the arraylist is not empty.
Each of the custom object.equals methods is pretty smart. They first test
for type (ie: typeof xxx is string) and then test for whatever we need to
match in the class properties to see if we actually have a match. This
works very well.
Now, the thing that makes it all come together is this: the function that
actually searches these arraylists has an overload for each of the different
arraylist collections. This way, we positively know what we can search on,
and when the function returns the class instance, it returns it CAST AS THE
ACTUAL CLASS, so we can use the dot nomenclature to obtain any other
property or access any other method of the class. The search function is
called FINDITEM and here is an example of how it might work: Let's say you
want to find the number of sick days employee 12345 has had year to date:

intNumSickDays = FINDITEM(alEmployeeCollection, new Employee,
12345).NumSickDays

That's it. Pretty easy and straightforward. The first param is the
arraylist collection, the second is just a instance of the custom class
we're looking for (used to identify the proper overload), and the third
param is what we're searching for. Notice that we are accessing the
NumOfSickDays property DIRECTLY from the FindItem function. Better yet,
since our custom classes can be nested (as the example above) this search
function CAN ALSO BE NESTED! Complex, multilevel, searches through
multiple arraylists with one easily understood statement. It doesn't get
much better than that!

We have estimated that by using this technique we will save hundreds of
manhours in coding over the development of the project (think $$$), not to
mention that our implimentation will be extremely extensible (everythings
stored in arraylists, which can be expanded), and extremely reliable
(basically one function to call to retrieve any data). The only downside
to this would be performance. However, we made the decision to go with the
easy to use, bulletproof code because next year the computers will be twice
as fast as today anyway, so what the heck.

Well, Jay, that's my case. Hope I've made a convincing one...

John



"Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
news:Oj**************@TK2MSFTNGP15.phx.gbl...
John,
| 2) If you pass anything other than an instance of your custom class to
the
| indexof method (even if your object.equals code would know how to handle
it)
| the indexof method will always return -1 (not found).
As I told Tom: I would expect that! As my understanding is that
Object.Equals should only succeed if both types are identical or at least
derived types. The Point example on the link I gave earlier demonstrates
this "rule", however I don't see the "rule" spelled out...

Even with Derived types there is risk involved will allowing the
comparison...

| So what do you do if you have coded some intelligent object.equals
methods
| and want to take advantage of them?
Unfortunately your "intelligent object.equals", now is comparing apples to
auto parts. Comparing apples to auto parts is not really logical
("intelligent"). I can see comparing an Apple to an Orange, as they are
both
fruits. However! An Apple cannot be an Orange, only attributes of the
Apple
can be the same as attributes of the Orange, ergo you should be comparing
the attributes of the Apple & Orange instead of attempting to compare the
Apple & Orange directly!

| Anyway, that's it. The above is based on my experimentation and works
fine
| for me... I hope this will help anybody else that is having issues with
the
| arraylist.indexof functionality.
ArrayList.IndexOf seems to work as I would expect it to! As I showed in my
sample earlier I don't allow my Object.Equals to compare objects of
different types, (Person <> String). If I needed to search the ArrayList
for
an object with a specific attribute I would define an alternate IndexOf
(with a specific name) that did the look up.
Public Function SearchForFirstName(name As String) As Integer
For i As Integer = 0 To Me.Count - 1
If Me.Item(i).FirstName = name Then
Return index
End If
Next
Return -1
End Function

As its obvious that SearchForFirstName is searching for an object with a
specific first name.

If the object supported implicit or explicit conversion between types
(current C# or VB.NET 2005 overloaded Widening or Narrowing CType
operators), such as a String can be widened to a Categoryobject. I would
do
this conversion before calling the IndexOf operator. Although there is a
conversion between String & Category, Category.Equals would still only
compare two Category values.

Hope this helps
Jay
"JohnR" <Jo******@hotmail.com> wrote in message
news:Lq7ce.2139$pc7.327@trndny05...
| OK, first I want to thank all that contributed to this conversation.
after
| much experimenting I have (I think) narrowed down what is going on
| concerning the ARRAYLIST.INDEXOF functionality.
|
|
|
| 1) in a normal arraylist containing custom class instances, if you pass
an
| instance of that custom class to the indexof method, it all works as
| expected.
|
| Example: x = arraylist.indexof(mycustomclass)
|
| Indeed, the overridden object.equals method in your custom class is
called
| as verified by a breakpoint in the code.
|
|
|
| 2) If you pass anything other than an instance of your custom class to
the
| indexof method (even if your object.equals code would know how to handle
it)
| the indexof method will always return -1 (not found).
|
|
|
| Example: x = arraylist.indexof(integer) will always
return -1
|
|
|
| I'm guessing that the standard indexof method initially checks the type
of
| the parameter and if it's not the same as the type contained in the
| arraylist it chooses not to continue by calling object.equals. it just
| gives up and returns a -1. The standard indexof method knows that the
| standard object.equals method expects an instance of the 'myclass' class
and
| does not allow for the possibility that you have overridden the
| object.equals method with a more intelligent one.
|
|
|
| So what do you do if you have coded some intelligent object.equals
methods
| and want to take advantage of them?
|
| Example: indexof(myclass) or indexof("string") or
indexof(integer)
| could all
|
| work because my object.equals method tests for the 'typeof'
| parameter passed
|
| and would handle each case appropriately.
|
|
|
| What you need to do is create a custom Arraylist class (ie: MyArraylist)
| which inherits Arraylist and overrides the indexof method as follows:
|
|
|
| Public Class MyArraylist
|
| Inherits ArrayList
|
| Public Overloads Overrides Function indexof(ByVal obj As Object)
As
| Integer
|
| If Me.Count = 0 Then Return -1
|
| For i As Integer = 0 To Me.Count - 1
|
| If Me.Item(i).Equals(obj) Then
|
| Return i
|
| End If
|
| Next
|
| Return -1
|
| End Function
|
| End Class
|
|
|
| This overridden indexof method does not care about the type of the
parameter
| passed to it. As long as the arraylist is not empty (me.count >0) it
will
| call the object.equals method and you will get the results you expect.
| Using this custom arraylist for your collection of objects gives you a
| tremendous amount of flexibility and greatly simplifies application code
| that you need to grab a particular class instance out of the arraylist,
| since you can "identify" the class instance you want by as many ways you
can
| think of (as long as they are properly handled in you custom
object.equals
| method!).
|
|
|
| Anyway, that's it. The above is based on my experimentation and works
fine
| for me... I hope this will help anybody else that is having issues with
the
| arraylist.indexof functionality.
|
|
|
| John
|
|
|
|
|
|
|
|

Nov 21 '05 #14

P: n/a
John,
| So the question (and it is a very serious question) is this: how can we
| easily code a retrieval process that will retrieve a specific instance of
a
| custom class that is stored in one of the arraylists.
It sounds like you really want to use a HashTable, instead of an ArrayList.

The key to the hashtable would be JobCategory. The value of the hashtable
would be the Employee. Of course the downside would be needing

Rather then inheriting from ArrayList directly I would suggest you inherit
from DictionaryBase or CollectionBase or a class that derives from
DictionaryBase or CollectionBase instead. This allows better encapsulation &
more type safety...

If you can search by multiple criteria I would consider defining a single
Search method, that accepts a Criteria parameter. This Criteria parameter
could either be a Delegate that knew about what attributes to look for or it
could be a type hierarchy itself... In this case I would consider
overloading the IndexOf method, as the overloaded method would include the
criteria. The Criteria parameter would enable polymorphism & should
"simplify" your code.

Something like:

Public Class Person

Public Shared ReadOnly CompareName As PersonCriteria = AddressOf
DoCompareName
Public Shared ReadOnly CompareJobCategory As PersonCriteria =
AddressOf DoCompareJobCategory

Public ReadOnly Name As String
Public ReadOnly JobCategory As String

Public Sub New(ByVal name As String, ByVal jobCategory As String)
Me.Name = name
Me.JobCategory = jobCategory
End Sub

Private Shared Function DoCompareName(ByVal item As Object, ByVal
value As Object) As Boolean
Return CompareName(DirectCast(item, Person), value)
End Function

Private Shared Function DoCompareName(ByVal item As Person, ByVal
value As Object) As Boolean
Return item.Name.Equals(value)
End Function

Private Shared Function DoCompareJobCategory(ByVal item As Object,
ByVal value As Object) As Boolean
Return CompareJobCategory(DirectCast(item, Person), value)
End Function

Private Shared Function DoCompareJobCategory(ByVal item As Person,
ByVal value As Object) As Boolean
Return item.JobCategory.Equals(value)
End Function

End Class

Public Class PersonCollection
Inherits CollectionBase

Default Public ReadOnly Property Item(ByVal index As Integer) As
Person
Get
Return DirectCast(Me.InnerList(index), Person)
End Get
End Property

Public Sub Add(ByVal person As Person)
Me.InnerList.Add(person)
End Sub

Public Function IndexOf(ByVal value As Object) As Integer
Return MyBase.InnerList.IndexOf(value)
End Function

Public Function IndexOf(ByVal value As Object, ByVal criteria As
Criteria) As Integer
For index As Integer = 0 To Me.Count - 1
If criteria.Invoke(value, Me.InnerList(index)) Then
Return index
End If
Next
Return -1
End Function

Public Function IndexOf(ByVal value As Object, ByVal criteria As
PersonCriteria) As Integer
For index As Integer = 0 To Me.Count - 1
If criteria.Invoke(Me(index), value) Then
Return index
End If
Next
Return -1
End Function

End Class

Public Sub Main()
Dim list As New PersonCollection
list.Add(New Person("jay", "mvp"))
list.Add(New Person("john", "programmer"))

Dim index As Integer

index = list.IndexOf("jay", Person.CompareName)
index = list.IndexOf("programmer", Person.CompareJobCategory)

End Sub
The Criteria delegate is the most general, however it is the least type
safe. The PersonCriteria is Person specific, it is more type safe. I believe
you will need to wait for VS.NET 2005 (aka Whidbey, due out later in 2005
http://lab.msdn.microsoft.com/vs2005/), to get the most type safe with
Delegates. I'll see if I can come up with an example of the above with
Generics later... System.Array.Find is an example of using delegates
http://msdn2.microsoft.com/library/d...us,vs.80).aspx

You only need to implement Criteria for all your classes or you need to
implement a *Type*Criteria for each of your classes. In other words its one
or the other, I just wanted to show both.

The Person.DoCompareName & Person.DoCompareJobCategory function know how to
compare a specific attribute of the Person object to a specific value.
Person.CompareName & Person.CompareJobCategory enable you to avoid needing
AddressOf all over the place.

The PersonCollection.IndexOf(Object, Criteria) &
PersonCollection.IndexOf(Object, PersonCriteria) calls the routine you give
it to compare an attribute of the current object with the requested value...

NOTE: Rather then return the IndexOf the item, I would consider finding the
Item itself.

Public Function Find(ByVal value As Object, ByVal criteria As
PersonCriteria) As Person
For Each item As Person In Me.InnerList
If criteria(item, value) Then
Return item
End If
Next
End Function

Dim foundPerson As Person = list.Find("jay", Person.CompareName)
My concern is that your current design is "Programming by Coincidence" that
overriding Object.Equals just happened to work, now that you are trying to
do ArrayList.IndexOf it doesn't work, so you are looking for a workaround to
get it to work, rather then finding a "cleaner" solution.
http://www.pragmaticprogrammer.com/p...incidence.html

Also its "by Coincidence" as you can tell the field to compare to, based on
the type of parameter to Equals. What happens when you have two attributes
that are strings that you want to compare to? Such as in my example?

| Each of the custom object.equals methods is pretty smart. They first test
| for type (ie: typeof xxx is string) and then test for whatever we need to
| match in the class properties to see if we actually have a match. This
| works very well.
But they are not really that smart, as they don't play well with the
assumptions place on Equals. specifically the bullet point that states
Object.Equals is defined such that "if x.Equals(y) return the same value as
y.Equals(x)".

http://msdn.microsoft.com/library/de...ualstopic1.asp

Also I suspect your Equals method is one long If, ElseIF, Else statement,
which is a good indication that you want to consider "Replace Conditional
with Polymorphism" refactoring.
http://www.refactoring.com/catalog/r...ymorphism.html

Hope this helps
Jay

Hope this helps
Jay

"JohnR" <Jo******@hotmail.com> wrote in message
news:aRDce.1147$KP.566@trndny02...
| Hi Jay,
|
| I can appreciate your point of view... there are some good reasons to
| limit indexof to an apples to apples comparison. However, I'd like to
make
| my case as to why is can be valuable to have a more intelligent
| comparison.... and it's much more logical than, as you said, "comparing
| apples to auto parts". (now, why would anybody want to do that??)
|
| In our commercial application we have (so far) about 40 different custom
| classes which define the specific things the system will deal with. For
now
| lets say we have an Employee class, a Job category class, and an Employee
| Rating class.
| In our actual application virtually everything that is a custom class is
| stored in an arraylist so that it can be expanded at any time. In my
| example it means that you can start off with 15 job categories, and add 25
| more at a later date, without having to change 1 line of code. In some
| classes we set up an ENUM for ease and clarity of coding, and some ENUMs
| have 80 to 90 entries. To make matters more interesting, it is very
common
| that a class has a property that is another custom class. In the example
| you could imagine that an instance of the Employee class has a property
that
| is an instance of the JobCategory class.
| So the question (and it is a very serious question) is this: how can we
| easily code a retrieval process that will retrieve a specific instance of
a
| custom class that is stored in one of the arraylists.
| In different situations we may have different 'bits' of information to
| identify the instance we want. For example, we might want to search for a
| Job Category of "17" (that's it's unique job code) OR we may want to
search
| for a Job Category of "Teacher" (that's it's unique name). Either one is
| enough to uniquely identify the instance of the JobCategory class we are
| interested in. Now take this simple example and multiply it 100 fold and
| you begin to see why having a separate indexof for each possible way we
want
| to search would quickly get out of control.
| The solution we are using involves a derived arraylist that has overridden
| the indexof method. All of our class instances are stored in these custom
| arraylists. The indexof method will call the object.equals method as long
| as the arraylist is not empty.
| Each of the custom object.equals methods is pretty smart. They first test
| for type (ie: typeof xxx is string) and then test for whatever we need to
| match in the class properties to see if we actually have a match. This
| works very well.
| Now, the thing that makes it all come together is this: the function that
| actually searches these arraylists has an overload for each of the
different
| arraylist collections. This way, we positively know what we can search
on,
| and when the function returns the class instance, it returns it CAST AS
THE
| ACTUAL CLASS, so we can use the dot nomenclature to obtain any other
| property or access any other method of the class. The search function is
| called FINDITEM and here is an example of how it might work: Let's say
you
| want to find the number of sick days employee 12345 has had year to date:
|
| intNumSickDays = FINDITEM(alEmployeeCollection, new Employee,
| 12345).NumSickDays
|
| That's it. Pretty easy and straightforward. The first param is the
| arraylist collection, the second is just a instance of the custom class
| we're looking for (used to identify the proper overload), and the third
| param is what we're searching for. Notice that we are accessing the
| NumOfSickDays property DIRECTLY from the FindItem function. Better yet,
| since our custom classes can be nested (as the example above) this search
| function CAN ALSO BE NESTED! Complex, multilevel, searches through
| multiple arraylists with one easily understood statement. It doesn't get
| much better than that!
|
| We have estimated that by using this technique we will save hundreds of
| manhours in coding over the development of the project (think $$$), not to
| mention that our implimentation will be extremely extensible (everythings
| stored in arraylists, which can be expanded), and extremely reliable
| (basically one function to call to retrieve any data). The only downside
| to this would be performance. However, we made the decision to go with
the
| easy to use, bulletproof code because next year the computers will be
twice
| as fast as today anyway, so what the heck.
|
| Well, Jay, that's my case. Hope I've made a convincing one...
|
| John
|
|
|
|
|
|
|
| "Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
| news:Oj**************@TK2MSFTNGP15.phx.gbl...
| > John,
| > | 2) If you pass anything other than an instance of your custom class to
| > the
| > | indexof method (even if your object.equals code would know how to
handle
| > it)
| > | the indexof method will always return -1 (not found).
| > As I told Tom: I would expect that! As my understanding is that
| > Object.Equals should only succeed if both types are identical or at
least
| > derived types. The Point example on the link I gave earlier demonstrates
| > this "rule", however I don't see the "rule" spelled out...
| >
| > Even with Derived types there is risk involved will allowing the
| > comparison...
| >
| > | So what do you do if you have coded some intelligent object.equals
| > methods
| > | and want to take advantage of them?
| > Unfortunately your "intelligent object.equals", now is comparing apples
to
| > auto parts. Comparing apples to auto parts is not really logical
| > ("intelligent"). I can see comparing an Apple to an Orange, as they are
| > both
| > fruits. However! An Apple cannot be an Orange, only attributes of the
| > Apple
| > can be the same as attributes of the Orange, ergo you should be
comparing
| > the attributes of the Apple & Orange instead of attempting to compare
the
| > Apple & Orange directly!
| >
| > | Anyway, that's it. The above is based on my experimentation and works
| > fine
| > | for me... I hope this will help anybody else that is having issues
with
| > the
| > | arraylist.indexof functionality.
| > ArrayList.IndexOf seems to work as I would expect it to! As I showed in
my
| > sample earlier I don't allow my Object.Equals to compare objects of
| > different types, (Person <> String). If I needed to search the ArrayList
| > for
| > an object with a specific attribute I would define an alternate IndexOf
| > (with a specific name) that did the look up.
| >
| >
| > Public Function SearchForFirstName(name As String) As Integer
| > For i As Integer = 0 To Me.Count - 1
| > If Me.Item(i).FirstName = name Then
| > Return index
| > End If
| > Next
| > Return -1
| > End Function
| >
| > As its obvious that SearchForFirstName is searching for an object with a
| > specific first name.
| >
| > If the object supported implicit or explicit conversion between types
| > (current C# or VB.NET 2005 overloaded Widening or Narrowing CType
| > operators), such as a String can be widened to a Categoryobject. I would
| > do
| > this conversion before calling the IndexOf operator. Although there is a
| > conversion between String & Category, Category.Equals would still only
| > compare two Category values.
| >
| > Hope this helps
| > Jay
| >
| >
| > "JohnR" <Jo******@hotmail.com> wrote in message
| > news:Lq7ce.2139$pc7.327@trndny05...
| > | OK, first I want to thank all that contributed to this conversation.
| > after
| > | much experimenting I have (I think) narrowed down what is going on
| > | concerning the ARRAYLIST.INDEXOF functionality.
| > |
| > |
| > |
| > | 1) in a normal arraylist containing custom class instances, if you
pass
| > an
| > | instance of that custom class to the indexof method, it all works as
| > | expected.
| > |
| > | Example: x = arraylist.indexof(mycustomclass)
| > |
| > | Indeed, the overridden object.equals method in your custom class is
| > called
| > | as verified by a breakpoint in the code.
| > |
| > |
| > |
| > | 2) If you pass anything other than an instance of your custom class to
| > the
| > | indexof method (even if your object.equals code would know how to
handle
| > it)
| > | the indexof method will always return -1 (not found).
| > |
| > |
| > |
| > | Example: x = arraylist.indexof(integer) will always
| > return -1
| > |
| > |
| > |
| > | I'm guessing that the standard indexof method initially checks the
type
| > of
| > | the parameter and if it's not the same as the type contained in the
| > | arraylist it chooses not to continue by calling object.equals. it
just
| > | gives up and returns a -1. The standard indexof method knows that
the
| > | standard object.equals method expects an instance of the 'myclass'
class
| > and
| > | does not allow for the possibility that you have overridden the
| > | object.equals method with a more intelligent one.
| > |
| > |
| > |
| > | So what do you do if you have coded some intelligent object.equals
| > methods
| > | and want to take advantage of them?
| > |
| > | Example: indexof(myclass) or indexof("string") or
| > indexof(integer)
| > | could all
| > |
| > | work because my object.equals method tests for the 'typeof'
| > | parameter passed
| > |
| > | and would handle each case appropriately.
| > |
| > |
| > |
| > | What you need to do is create a custom Arraylist class (ie:
MyArraylist)
| > | which inherits Arraylist and overrides the indexof method as follows:
| > |
| > |
| > |
| > | Public Class MyArraylist
| > |
| > | Inherits ArrayList
| > |
| > | Public Overloads Overrides Function indexof(ByVal obj As
Object)
| > As
| > | Integer
| > |
| > | If Me.Count = 0 Then Return -1
| > |
| > | For i As Integer = 0 To Me.Count - 1
| > |
| > | If Me.Item(i).Equals(obj) Then
| > |
| > | Return i
| > |
| > | End If
| > |
| > | Next
| > |
| > | Return -1
| > |
| > | End Function
| > |
| > | End Class
| > |
| > |
| > |
| > | This overridden indexof method does not care about the type of the
| > parameter
| > | passed to it. As long as the arraylist is not empty (me.count >0) it
| > will
| > | call the object.equals method and you will get the results you expect.
| > | Using this custom arraylist for your collection of objects gives you a
| > | tremendous amount of flexibility and greatly simplifies application
code
| > | that you need to grab a particular class instance out of the
arraylist,
| > | since you can "identify" the class instance you want by as many ways
you
| > can
| > | think of (as long as they are properly handled in you custom
| > object.equals
| > | method!).
| > |
| > |
| > |
| > | Anyway, that's it. The above is based on my experimentation and works
| > fine
| > | for me... I hope this will help anybody else that is having issues
with
| > the
| > | arraylist.indexof functionality.
| > |
| > |
| > |
| > | John
| > |
| > |
| > |
| > |
| > |
| > |
| > |
| > |
| >
| >
|
|
Nov 21 '05 #15

P: n/a
Doh!

I seem to have missed the Delegates themselves:

Public Delegate Function Criteria(ByVal item As Object, ByVal value As
Object) As Boolean
Public Delegate Function PersonCriteria(ByVal item As Person, ByVal
value As Object) As Boolean

Hope this helps
Jay

"Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
news:uS*************@tk2msftngp13.phx.gbl...
| John,
|| So the question (and it is a very serious question) is this: how can we
|| easily code a retrieval process that will retrieve a specific instance of
| a
|| custom class that is stored in one of the arraylists.
| It sounds like you really want to use a HashTable, instead of an
ArrayList.
|
| The key to the hashtable would be JobCategory. The value of the hashtable
| would be the Employee. Of course the downside would be needing
|
| Rather then inheriting from ArrayList directly I would suggest you inherit
| from DictionaryBase or CollectionBase or a class that derives from
| DictionaryBase or CollectionBase instead. This allows better encapsulation
&
| more type safety...
|
| If you can search by multiple criteria I would consider defining a single
| Search method, that accepts a Criteria parameter. This Criteria parameter
| could either be a Delegate that knew about what attributes to look for or
it
| could be a type hierarchy itself... In this case I would consider
| overloading the IndexOf method, as the overloaded method would include the
| criteria. The Criteria parameter would enable polymorphism & should
| "simplify" your code.
|
| Something like:
|
| Public Class Person
|
| Public Shared ReadOnly CompareName As PersonCriteria = AddressOf
| DoCompareName
| Public Shared ReadOnly CompareJobCategory As PersonCriteria =
| AddressOf DoCompareJobCategory
|
| Public ReadOnly Name As String
| Public ReadOnly JobCategory As String
|
| Public Sub New(ByVal name As String, ByVal jobCategory As String)
| Me.Name = name
| Me.JobCategory = jobCategory
| End Sub
|
| Private Shared Function DoCompareName(ByVal item As Object, ByVal
| value As Object) As Boolean
| Return CompareName(DirectCast(item, Person), value)
| End Function
|
| Private Shared Function DoCompareName(ByVal item As Person, ByVal
| value As Object) As Boolean
| Return item.Name.Equals(value)
| End Function
|
| Private Shared Function DoCompareJobCategory(ByVal item As Object,
| ByVal value As Object) As Boolean
| Return CompareJobCategory(DirectCast(item, Person), value)
| End Function
|
| Private Shared Function DoCompareJobCategory(ByVal item As Person,
| ByVal value As Object) As Boolean
| Return item.JobCategory.Equals(value)
| End Function
|
| End Class
|
| Public Class PersonCollection
| Inherits CollectionBase
|
| Default Public ReadOnly Property Item(ByVal index As Integer) As
| Person
| Get
| Return DirectCast(Me.InnerList(index), Person)
| End Get
| End Property
|
| Public Sub Add(ByVal person As Person)
| Me.InnerList.Add(person)
| End Sub
|
| Public Function IndexOf(ByVal value As Object) As Integer
| Return MyBase.InnerList.IndexOf(value)
| End Function
|
| Public Function IndexOf(ByVal value As Object, ByVal criteria As
| Criteria) As Integer
| For index As Integer = 0 To Me.Count - 1
| If criteria.Invoke(value, Me.InnerList(index)) Then
| Return index
| End If
| Next
| Return -1
| End Function
|
| Public Function IndexOf(ByVal value As Object, ByVal criteria As
| PersonCriteria) As Integer
| For index As Integer = 0 To Me.Count - 1
| If criteria.Invoke(Me(index), value) Then
| Return index
| End If
| Next
| Return -1
| End Function
|
| End Class
|
| Public Sub Main()
| Dim list As New PersonCollection
| list.Add(New Person("jay", "mvp"))
| list.Add(New Person("john", "programmer"))
|
| Dim index As Integer
|
| index = list.IndexOf("jay", Person.CompareName)
| index = list.IndexOf("programmer", Person.CompareJobCategory)
|
| End Sub
|
|
| The Criteria delegate is the most general, however it is the least type
| safe. The PersonCriteria is Person specific, it is more type safe. I
believe
| you will need to wait for VS.NET 2005 (aka Whidbey, due out later in 2005
| http://lab.msdn.microsoft.com/vs2005/), to get the most type safe with
| Delegates. I'll see if I can come up with an example of the above with
| Generics later... System.Array.Find is an example of using delegates
| http://msdn2.microsoft.com/library/d...us,vs.80).aspx
|
| You only need to implement Criteria for all your classes or you need to
| implement a *Type*Criteria for each of your classes. In other words its
one
| or the other, I just wanted to show both.
|
| The Person.DoCompareName & Person.DoCompareJobCategory function know how
to
| compare a specific attribute of the Person object to a specific value.
| Person.CompareName & Person.CompareJobCategory enable you to avoid needing
| AddressOf all over the place.
|
| The PersonCollection.IndexOf(Object, Criteria) &
| PersonCollection.IndexOf(Object, PersonCriteria) calls the routine you
give
| it to compare an attribute of the current object with the requested
value...
|
| NOTE: Rather then return the IndexOf the item, I would consider finding
the
| Item itself.
|
| Public Function Find(ByVal value As Object, ByVal criteria As
| PersonCriteria) As Person
| For Each item As Person In Me.InnerList
| If criteria(item, value) Then
| Return item
| End If
| Next
| End Function
|
| Dim foundPerson As Person = list.Find("jay", Person.CompareName)
|
|
| My concern is that your current design is "Programming by Coincidence"
that
| overriding Object.Equals just happened to work, now that you are trying to
| do ArrayList.IndexOf it doesn't work, so you are looking for a workaround
to
| get it to work, rather then finding a "cleaner" solution.
| http://www.pragmaticprogrammer.com/p...incidence.html
|
| Also its "by Coincidence" as you can tell the field to compare to, based
on
| the type of parameter to Equals. What happens when you have two attributes
| that are strings that you want to compare to? Such as in my example?
|
|| Each of the custom object.equals methods is pretty smart. They first
test
|| for type (ie: typeof xxx is string) and then test for whatever we need to
|| match in the class properties to see if we actually have a match. This
|| works very well.
| But they are not really that smart, as they don't play well with the
| assumptions place on Equals. specifically the bullet point that states
| Object.Equals is defined such that "if x.Equals(y) return the same value
as
| y.Equals(x)".
|
|
http://msdn.microsoft.com/library/de...ualstopic1.asp
|
| Also I suspect your Equals method is one long If, ElseIF, Else statement,
| which is a good indication that you want to consider "Replace Conditional
| with Polymorphism" refactoring.
| http://www.refactoring.com/catalog/r...ymorphism.html
|
| Hope this helps
| Jay
|
|
|
| Hope this helps
| Jay
|
| "JohnR" <Jo******@hotmail.com> wrote in message
| news:aRDce.1147$KP.566@trndny02...
|| Hi Jay,
||
|| I can appreciate your point of view... there are some good reasons to
|| limit indexof to an apples to apples comparison. However, I'd like to
| make
|| my case as to why is can be valuable to have a more intelligent
|| comparison.... and it's much more logical than, as you said, "comparing
|| apples to auto parts". (now, why would anybody want to do that??)
||
|| In our commercial application we have (so far) about 40 different custom
|| classes which define the specific things the system will deal with. For
| now
|| lets say we have an Employee class, a Job category class, and an Employee
|| Rating class.
|| In our actual application virtually everything that is a custom class is
|| stored in an arraylist so that it can be expanded at any time. In my
|| example it means that you can start off with 15 job categories, and add
25
|| more at a later date, without having to change 1 line of code. In some
|| classes we set up an ENUM for ease and clarity of coding, and some ENUMs
|| have 80 to 90 entries. To make matters more interesting, it is very
| common
|| that a class has a property that is another custom class. In the example
|| you could imagine that an instance of the Employee class has a property
| that
|| is an instance of the JobCategory class.
|| So the question (and it is a very serious question) is this: how can we
|| easily code a retrieval process that will retrieve a specific instance of
| a
|| custom class that is stored in one of the arraylists.
|| In different situations we may have different 'bits' of information to
|| identify the instance we want. For example, we might want to search for
a
|| Job Category of "17" (that's it's unique job code) OR we may want to
| search
|| for a Job Category of "Teacher" (that's it's unique name). Either one
is
|| enough to uniquely identify the instance of the JobCategory class we are
|| interested in. Now take this simple example and multiply it 100 fold
and
|| you begin to see why having a separate indexof for each possible way we
| want
|| to search would quickly get out of control.
|| The solution we are using involves a derived arraylist that has
overridden
|| the indexof method. All of our class instances are stored in these
custom
|| arraylists. The indexof method will call the object.equals method as
long
|| as the arraylist is not empty.
|| Each of the custom object.equals methods is pretty smart. They first
test
|| for type (ie: typeof xxx is string) and then test for whatever we need to
|| match in the class properties to see if we actually have a match. This
|| works very well.
|| Now, the thing that makes it all come together is this: the function
that
|| actually searches these arraylists has an overload for each of the
| different
|| arraylist collections. This way, we positively know what we can search
| on,
|| and when the function returns the class instance, it returns it CAST AS
| THE
|| ACTUAL CLASS, so we can use the dot nomenclature to obtain any other
|| property or access any other method of the class. The search function is
|| called FINDITEM and here is an example of how it might work: Let's say
| you
|| want to find the number of sick days employee 12345 has had year to date:
||
|| intNumSickDays = FINDITEM(alEmployeeCollection, new Employee,
|| 12345).NumSickDays
||
|| That's it. Pretty easy and straightforward. The first param is the
|| arraylist collection, the second is just a instance of the custom class
|| we're looking for (used to identify the proper overload), and the third
|| param is what we're searching for. Notice that we are accessing the
|| NumOfSickDays property DIRECTLY from the FindItem function. Better yet,
|| since our custom classes can be nested (as the example above) this search
|| function CAN ALSO BE NESTED! Complex, multilevel, searches through
|| multiple arraylists with one easily understood statement. It doesn't get
|| much better than that!
||
|| We have estimated that by using this technique we will save hundreds of
|| manhours in coding over the development of the project (think $$$), not
to
|| mention that our implimentation will be extremely extensible (everythings
|| stored in arraylists, which can be expanded), and extremely reliable
|| (basically one function to call to retrieve any data). The only
downside
|| to this would be performance. However, we made the decision to go with
| the
|| easy to use, bulletproof code because next year the computers will be
| twice
|| as fast as today anyway, so what the heck.
||
|| Well, Jay, that's my case. Hope I've made a convincing one...
||
|| John
||
||
||
||
||
||
||
|| "Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
|| news:Oj**************@TK2MSFTNGP15.phx.gbl...
|| > John,
|| > | 2) If you pass anything other than an instance of your custom class
to
|| > the
|| > | indexof method (even if your object.equals code would know how to
| handle
|| > it)
|| > | the indexof method will always return -1 (not found).
|| > As I told Tom: I would expect that! As my understanding is that
|| > Object.Equals should only succeed if both types are identical or at
| least
|| > derived types. The Point example on the link I gave earlier
demonstrates
|| > this "rule", however I don't see the "rule" spelled out...
|| >
|| > Even with Derived types there is risk involved will allowing the
|| > comparison...
|| >
|| > | So what do you do if you have coded some intelligent object.equals
|| > methods
|| > | and want to take advantage of them?
|| > Unfortunately your "intelligent object.equals", now is comparing apples
| to
|| > auto parts. Comparing apples to auto parts is not really logical
|| > ("intelligent"). I can see comparing an Apple to an Orange, as they are
|| > both
|| > fruits. However! An Apple cannot be an Orange, only attributes of the
|| > Apple
|| > can be the same as attributes of the Orange, ergo you should be
| comparing
|| > the attributes of the Apple & Orange instead of attempting to compare
| the
|| > Apple & Orange directly!
|| >
|| > | Anyway, that's it. The above is based on my experimentation and works
|| > fine
|| > | for me... I hope this will help anybody else that is having issues
| with
|| > the
|| > | arraylist.indexof functionality.
|| > ArrayList.IndexOf seems to work as I would expect it to! As I showed in
| my
|| > sample earlier I don't allow my Object.Equals to compare objects of
|| > different types, (Person <> String). If I needed to search the
ArrayList
|| > for
|| > an object with a specific attribute I would define an alternate IndexOf
|| > (with a specific name) that did the look up.
|| >
|| >
|| > Public Function SearchForFirstName(name As String) As Integer
|| > For i As Integer = 0 To Me.Count - 1
|| > If Me.Item(i).FirstName = name Then
|| > Return index
|| > End If
|| > Next
|| > Return -1
|| > End Function
|| >
|| > As its obvious that SearchForFirstName is searching for an object with
a
|| > specific first name.
|| >
|| > If the object supported implicit or explicit conversion between types
|| > (current C# or VB.NET 2005 overloaded Widening or Narrowing CType
|| > operators), such as a String can be widened to a Categoryobject. I
would
|| > do
|| > this conversion before calling the IndexOf operator. Although there is
a
|| > conversion between String & Category, Category.Equals would still only
|| > compare two Category values.
|| >
|| > Hope this helps
|| > Jay
|| >
|| >
|| > "JohnR" <Jo******@hotmail.com> wrote in message
|| > news:Lq7ce.2139$pc7.327@trndny05...
|| > | OK, first I want to thank all that contributed to this conversation.
|| > after
|| > | much experimenting I have (I think) narrowed down what is going on
|| > | concerning the ARRAYLIST.INDEXOF functionality.
|| > |
|| > |
|| > |
|| > | 1) in a normal arraylist containing custom class instances, if you
| pass
|| > an
|| > | instance of that custom class to the indexof method, it all works as
|| > | expected.
|| > |
|| > | Example: x = arraylist.indexof(mycustomclass)
|| > |
|| > | Indeed, the overridden object.equals method in your custom class is
|| > called
|| > | as verified by a breakpoint in the code.
|| > |
|| > |
|| > |
|| > | 2) If you pass anything other than an instance of your custom class
to
|| > the
|| > | indexof method (even if your object.equals code would know how to
| handle
|| > it)
|| > | the indexof method will always return -1 (not found).
|| > |
|| > |
|| > |
|| > | Example: x = arraylist.indexof(integer) will always
|| > return -1
|| > |
|| > |
|| > |
|| > | I'm guessing that the standard indexof method initially checks the
| type
|| > of
|| > | the parameter and if it's not the same as the type contained in the
|| > | arraylist it chooses not to continue by calling object.equals. it
| just
|| > | gives up and returns a -1. The standard indexof method knows that
| the
|| > | standard object.equals method expects an instance of the 'myclass'
| class
|| > and
|| > | does not allow for the possibility that you have overridden the
|| > | object.equals method with a more intelligent one.
|| > |
|| > |
|| > |
|| > | So what do you do if you have coded some intelligent object.equals
|| > methods
|| > | and want to take advantage of them?
|| > |
|| > | Example: indexof(myclass) or indexof("string") or
|| > indexof(integer)
|| > | could all
|| > |
|| > | work because my object.equals method tests for the 'typeof'
|| > | parameter passed
|| > |
|| > | and would handle each case appropriately.
|| > |
|| > |
|| > |
|| > | What you need to do is create a custom Arraylist class (ie:
| MyArraylist)
|| > | which inherits Arraylist and overrides the indexof method as follows:
|| > |
|| > |
|| > |
|| > | Public Class MyArraylist
|| > |
|| > | Inherits ArrayList
|| > |
|| > | Public Overloads Overrides Function indexof(ByVal obj As
| Object)
|| > As
|| > | Integer
|| > |
|| > | If Me.Count = 0 Then Return -1
|| > |
|| > | For i As Integer = 0 To Me.Count - 1
|| > |
|| > | If Me.Item(i).Equals(obj) Then
|| > |
|| > | Return i
|| > |
|| > | End If
|| > |
|| > | Next
|| > |
|| > | Return -1
|| > |
|| > | End Function
|| > |
|| > | End Class
|| > |
|| > |
|| > |
|| > | This overridden indexof method does not care about the type of the
|| > parameter
|| > | passed to it. As long as the arraylist is not empty (me.count >0) it
|| > will
|| > | call the object.equals method and you will get the results you
expect.
|| > | Using this custom arraylist for your collection of objects gives you
a
|| > | tremendous amount of flexibility and greatly simplifies application
| code
|| > | that you need to grab a particular class instance out of the
| arraylist,
|| > | since you can "identify" the class instance you want by as many ways
| you
|| > can
|| > | think of (as long as they are properly handled in you custom
|| > object.equals
|| > | method!).
|| > |
|| > |
|| > |
|| > | Anyway, that's it. The above is based on my experimentation and works
|| > fine
|| > | for me... I hope this will help anybody else that is having issues
| with
|| > the
|| > | arraylist.indexof functionality.
|| > |
|| > |
|| > |
|| > | John
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| >
|| >
||
||
|
|
Nov 21 '05 #16

P: n/a
Doh!
It appears that I got this backwards:

| Public Function IndexOf(ByVal value As Object, ByVal criteria As
| Criteria) As Integer
| For index As Integer = 0 To Me.Count - 1

| *wrong* If criteria.Invoke(value, Me.InnerList(index)) Then

*correct* If criteria.Invoke(Me.InnerList(index), value) Then

| Return index
| End If
| Next
| Return -1
| End Function

Jay

"Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
news:uS*************@tk2msftngp13.phx.gbl...
| John,
|| So the question (and it is a very serious question) is this: how can we
|| easily code a retrieval process that will retrieve a specific instance of
| a
|| custom class that is stored in one of the arraylists.
| It sounds like you really want to use a HashTable, instead of an
ArrayList.
|
| The key to the hashtable would be JobCategory. The value of the hashtable
| would be the Employee. Of course the downside would be needing
|
| Rather then inheriting from ArrayList directly I would suggest you inherit
| from DictionaryBase or CollectionBase or a class that derives from
| DictionaryBase or CollectionBase instead. This allows better encapsulation
&
| more type safety...
|
| If you can search by multiple criteria I would consider defining a single
| Search method, that accepts a Criteria parameter. This Criteria parameter
| could either be a Delegate that knew about what attributes to look for or
it
| could be a type hierarchy itself... In this case I would consider
| overloading the IndexOf method, as the overloaded method would include the
| criteria. The Criteria parameter would enable polymorphism & should
| "simplify" your code.
|
| Something like:
|
| Public Class Person
|
| Public Shared ReadOnly CompareName As PersonCriteria = AddressOf
| DoCompareName
| Public Shared ReadOnly CompareJobCategory As PersonCriteria =
| AddressOf DoCompareJobCategory
|
| Public ReadOnly Name As String
| Public ReadOnly JobCategory As String
|
| Public Sub New(ByVal name As String, ByVal jobCategory As String)
| Me.Name = name
| Me.JobCategory = jobCategory
| End Sub
|
| Private Shared Function DoCompareName(ByVal item As Object, ByVal
| value As Object) As Boolean
| Return CompareName(DirectCast(item, Person), value)
| End Function
|
| Private Shared Function DoCompareName(ByVal item As Person, ByVal
| value As Object) As Boolean
| Return item.Name.Equals(value)
| End Function
|
| Private Shared Function DoCompareJobCategory(ByVal item As Object,
| ByVal value As Object) As Boolean
| Return CompareJobCategory(DirectCast(item, Person), value)
| End Function
|
| Private Shared Function DoCompareJobCategory(ByVal item As Person,
| ByVal value As Object) As Boolean
| Return item.JobCategory.Equals(value)
| End Function
|
| End Class
|
| Public Class PersonCollection
| Inherits CollectionBase
|
| Default Public ReadOnly Property Item(ByVal index As Integer) As
| Person
| Get
| Return DirectCast(Me.InnerList(index), Person)
| End Get
| End Property
|
| Public Sub Add(ByVal person As Person)
| Me.InnerList.Add(person)
| End Sub
|
| Public Function IndexOf(ByVal value As Object) As Integer
| Return MyBase.InnerList.IndexOf(value)
| End Function
|
| Public Function IndexOf(ByVal value As Object, ByVal criteria As
| Criteria) As Integer
| For index As Integer = 0 To Me.Count - 1
| If criteria.Invoke(value, Me.InnerList(index)) Then
| Return index
| End If
| Next
| Return -1
| End Function
|
| Public Function IndexOf(ByVal value As Object, ByVal criteria As
| PersonCriteria) As Integer
| For index As Integer = 0 To Me.Count - 1
| If criteria.Invoke(Me(index), value) Then
| Return index
| End If
| Next
| Return -1
| End Function
|
| End Class
|
| Public Sub Main()
| Dim list As New PersonCollection
| list.Add(New Person("jay", "mvp"))
| list.Add(New Person("john", "programmer"))
|
| Dim index As Integer
|
| index = list.IndexOf("jay", Person.CompareName)
| index = list.IndexOf("programmer", Person.CompareJobCategory)
|
| End Sub
|
|
| The Criteria delegate is the most general, however it is the least type
| safe. The PersonCriteria is Person specific, it is more type safe. I
believe
| you will need to wait for VS.NET 2005 (aka Whidbey, due out later in 2005
| http://lab.msdn.microsoft.com/vs2005/), to get the most type safe with
| Delegates. I'll see if I can come up with an example of the above with
| Generics later... System.Array.Find is an example of using delegates
| http://msdn2.microsoft.com/library/d...us,vs.80).aspx
|
| You only need to implement Criteria for all your classes or you need to
| implement a *Type*Criteria for each of your classes. In other words its
one
| or the other, I just wanted to show both.
|
| The Person.DoCompareName & Person.DoCompareJobCategory function know how
to
| compare a specific attribute of the Person object to a specific value.
| Person.CompareName & Person.CompareJobCategory enable you to avoid needing
| AddressOf all over the place.
|
| The PersonCollection.IndexOf(Object, Criteria) &
| PersonCollection.IndexOf(Object, PersonCriteria) calls the routine you
give
| it to compare an attribute of the current object with the requested
value...
|
| NOTE: Rather then return the IndexOf the item, I would consider finding
the
| Item itself.
|
| Public Function Find(ByVal value As Object, ByVal criteria As
| PersonCriteria) As Person
| For Each item As Person In Me.InnerList
| If criteria(item, value) Then
| Return item
| End If
| Next
| End Function
|
| Dim foundPerson As Person = list.Find("jay", Person.CompareName)
|
|
| My concern is that your current design is "Programming by Coincidence"
that
| overriding Object.Equals just happened to work, now that you are trying to
| do ArrayList.IndexOf it doesn't work, so you are looking for a workaround
to
| get it to work, rather then finding a "cleaner" solution.
| http://www.pragmaticprogrammer.com/p...incidence.html
|
| Also its "by Coincidence" as you can tell the field to compare to, based
on
| the type of parameter to Equals. What happens when you have two attributes
| that are strings that you want to compare to? Such as in my example?
|
|| Each of the custom object.equals methods is pretty smart. They first
test
|| for type (ie: typeof xxx is string) and then test for whatever we need to
|| match in the class properties to see if we actually have a match. This
|| works very well.
| But they are not really that smart, as they don't play well with the
| assumptions place on Equals. specifically the bullet point that states
| Object.Equals is defined such that "if x.Equals(y) return the same value
as
| y.Equals(x)".
|
|
http://msdn.microsoft.com/library/de...ualstopic1.asp
|
| Also I suspect your Equals method is one long If, ElseIF, Else statement,
| which is a good indication that you want to consider "Replace Conditional
| with Polymorphism" refactoring.
| http://www.refactoring.com/catalog/r...ymorphism.html
|
| Hope this helps
| Jay
|
|
|
| Hope this helps
| Jay
|
| "JohnR" <Jo******@hotmail.com> wrote in message
| news:aRDce.1147$KP.566@trndny02...
|| Hi Jay,
||
|| I can appreciate your point of view... there are some good reasons to
|| limit indexof to an apples to apples comparison. However, I'd like to
| make
|| my case as to why is can be valuable to have a more intelligent
|| comparison.... and it's much more logical than, as you said, "comparing
|| apples to auto parts". (now, why would anybody want to do that??)
||
|| In our commercial application we have (so far) about 40 different custom
|| classes which define the specific things the system will deal with. For
| now
|| lets say we have an Employee class, a Job category class, and an Employee
|| Rating class.
|| In our actual application virtually everything that is a custom class is
|| stored in an arraylist so that it can be expanded at any time. In my
|| example it means that you can start off with 15 job categories, and add
25
|| more at a later date, without having to change 1 line of code. In some
|| classes we set up an ENUM for ease and clarity of coding, and some ENUMs
|| have 80 to 90 entries. To make matters more interesting, it is very
| common
|| that a class has a property that is another custom class. In the example
|| you could imagine that an instance of the Employee class has a property
| that
|| is an instance of the JobCategory class.
|| So the question (and it is a very serious question) is this: how can we
|| easily code a retrieval process that will retrieve a specific instance of
| a
|| custom class that is stored in one of the arraylists.
|| In different situations we may have different 'bits' of information to
|| identify the instance we want. For example, we might want to search for
a
|| Job Category of "17" (that's it's unique job code) OR we may want to
| search
|| for a Job Category of "Teacher" (that's it's unique name). Either one
is
|| enough to uniquely identify the instance of the JobCategory class we are
|| interested in. Now take this simple example and multiply it 100 fold
and
|| you begin to see why having a separate indexof for each possible way we
| want
|| to search would quickly get out of control.
|| The solution we are using involves a derived arraylist that has
overridden
|| the indexof method. All of our class instances are stored in these
custom
|| arraylists. The indexof method will call the object.equals method as
long
|| as the arraylist is not empty.
|| Each of the custom object.equals methods is pretty smart. They first
test
|| for type (ie: typeof xxx is string) and then test for whatever we need to
|| match in the class properties to see if we actually have a match. This
|| works very well.
|| Now, the thing that makes it all come together is this: the function
that
|| actually searches these arraylists has an overload for each of the
| different
|| arraylist collections. This way, we positively know what we can search
| on,
|| and when the function returns the class instance, it returns it CAST AS
| THE
|| ACTUAL CLASS, so we can use the dot nomenclature to obtain any other
|| property or access any other method of the class. The search function is
|| called FINDITEM and here is an example of how it might work: Let's say
| you
|| want to find the number of sick days employee 12345 has had year to date:
||
|| intNumSickDays = FINDITEM(alEmployeeCollection, new Employee,
|| 12345).NumSickDays
||
|| That's it. Pretty easy and straightforward. The first param is the
|| arraylist collection, the second is just a instance of the custom class
|| we're looking for (used to identify the proper overload), and the third
|| param is what we're searching for. Notice that we are accessing the
|| NumOfSickDays property DIRECTLY from the FindItem function. Better yet,
|| since our custom classes can be nested (as the example above) this search
|| function CAN ALSO BE NESTED! Complex, multilevel, searches through
|| multiple arraylists with one easily understood statement. It doesn't get
|| much better than that!
||
|| We have estimated that by using this technique we will save hundreds of
|| manhours in coding over the development of the project (think $$$), not
to
|| mention that our implimentation will be extremely extensible (everythings
|| stored in arraylists, which can be expanded), and extremely reliable
|| (basically one function to call to retrieve any data). The only
downside
|| to this would be performance. However, we made the decision to go with
| the
|| easy to use, bulletproof code because next year the computers will be
| twice
|| as fast as today anyway, so what the heck.
||
|| Well, Jay, that's my case. Hope I've made a convincing one...
||
|| John
||
||
||
||
||
||
||
|| "Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
|| news:Oj**************@TK2MSFTNGP15.phx.gbl...
|| > John,
|| > | 2) If you pass anything other than an instance of your custom class
to
|| > the
|| > | indexof method (even if your object.equals code would know how to
| handle
|| > it)
|| > | the indexof method will always return -1 (not found).
|| > As I told Tom: I would expect that! As my understanding is that
|| > Object.Equals should only succeed if both types are identical or at
| least
|| > derived types. The Point example on the link I gave earlier
demonstrates
|| > this "rule", however I don't see the "rule" spelled out...
|| >
|| > Even with Derived types there is risk involved will allowing the
|| > comparison...
|| >
|| > | So what do you do if you have coded some intelligent object.equals
|| > methods
|| > | and want to take advantage of them?
|| > Unfortunately your "intelligent object.equals", now is comparing apples
| to
|| > auto parts. Comparing apples to auto parts is not really logical
|| > ("intelligent"). I can see comparing an Apple to an Orange, as they are
|| > both
|| > fruits. However! An Apple cannot be an Orange, only attributes of the
|| > Apple
|| > can be the same as attributes of the Orange, ergo you should be
| comparing
|| > the attributes of the Apple & Orange instead of attempting to compare
| the
|| > Apple & Orange directly!
|| >
|| > | Anyway, that's it. The above is based on my experimentation and works
|| > fine
|| > | for me... I hope this will help anybody else that is having issues
| with
|| > the
|| > | arraylist.indexof functionality.
|| > ArrayList.IndexOf seems to work as I would expect it to! As I showed in
| my
|| > sample earlier I don't allow my Object.Equals to compare objects of
|| > different types, (Person <> String). If I needed to search the
ArrayList
|| > for
|| > an object with a specific attribute I would define an alternate IndexOf
|| > (with a specific name) that did the look up.
|| >
|| >
|| > Public Function SearchForFirstName(name As String) As Integer
|| > For i As Integer = 0 To Me.Count - 1
|| > If Me.Item(i).FirstName = name Then
|| > Return index
|| > End If
|| > Next
|| > Return -1
|| > End Function
|| >
|| > As its obvious that SearchForFirstName is searching for an object with
a
|| > specific first name.
|| >
|| > If the object supported implicit or explicit conversion between types
|| > (current C# or VB.NET 2005 overloaded Widening or Narrowing CType
|| > operators), such as a String can be widened to a Categoryobject. I
would
|| > do
|| > this conversion before calling the IndexOf operator. Although there is
a
|| > conversion between String & Category, Category.Equals would still only
|| > compare two Category values.
|| >
|| > Hope this helps
|| > Jay
|| >
|| >
|| > "JohnR" <Jo******@hotmail.com> wrote in message
|| > news:Lq7ce.2139$pc7.327@trndny05...
|| > | OK, first I want to thank all that contributed to this conversation.
|| > after
|| > | much experimenting I have (I think) narrowed down what is going on
|| > | concerning the ARRAYLIST.INDEXOF functionality.
|| > |
|| > |
|| > |
|| > | 1) in a normal arraylist containing custom class instances, if you
| pass
|| > an
|| > | instance of that custom class to the indexof method, it all works as
|| > | expected.
|| > |
|| > | Example: x = arraylist.indexof(mycustomclass)
|| > |
|| > | Indeed, the overridden object.equals method in your custom class is
|| > called
|| > | as verified by a breakpoint in the code.
|| > |
|| > |
|| > |
|| > | 2) If you pass anything other than an instance of your custom class
to
|| > the
|| > | indexof method (even if your object.equals code would know how to
| handle
|| > it)
|| > | the indexof method will always return -1 (not found).
|| > |
|| > |
|| > |
|| > | Example: x = arraylist.indexof(integer) will always
|| > return -1
|| > |
|| > |
|| > |
|| > | I'm guessing that the standard indexof method initially checks the
| type
|| > of
|| > | the parameter and if it's not the same as the type contained in the
|| > | arraylist it chooses not to continue by calling object.equals. it
| just
|| > | gives up and returns a -1. The standard indexof method knows that
| the
|| > | standard object.equals method expects an instance of the 'myclass'
| class
|| > and
|| > | does not allow for the possibility that you have overridden the
|| > | object.equals method with a more intelligent one.
|| > |
|| > |
|| > |
|| > | So what do you do if you have coded some intelligent object.equals
|| > methods
|| > | and want to take advantage of them?
|| > |
|| > | Example: indexof(myclass) or indexof("string") or
|| > indexof(integer)
|| > | could all
|| > |
|| > | work because my object.equals method tests for the 'typeof'
|| > | parameter passed
|| > |
|| > | and would handle each case appropriately.
|| > |
|| > |
|| > |
|| > | What you need to do is create a custom Arraylist class (ie:
| MyArraylist)
|| > | which inherits Arraylist and overrides the indexof method as follows:
|| > |
|| > |
|| > |
|| > | Public Class MyArraylist
|| > |
|| > | Inherits ArrayList
|| > |
|| > | Public Overloads Overrides Function indexof(ByVal obj As
| Object)
|| > As
|| > | Integer
|| > |
|| > | If Me.Count = 0 Then Return -1
|| > |
|| > | For i As Integer = 0 To Me.Count - 1
|| > |
|| > | If Me.Item(i).Equals(obj) Then
|| > |
|| > | Return i
|| > |
|| > | End If
|| > |
|| > | Next
|| > |
|| > | Return -1
|| > |
|| > | End Function
|| > |
|| > | End Class
|| > |
|| > |
|| > |
|| > | This overridden indexof method does not care about the type of the
|| > parameter
|| > | passed to it. As long as the arraylist is not empty (me.count >0) it
|| > will
|| > | call the object.equals method and you will get the results you
expect.
|| > | Using this custom arraylist for your collection of objects gives you
a
|| > | tremendous amount of flexibility and greatly simplifies application
| code
|| > | that you need to grab a particular class instance out of the
| arraylist,
|| > | since you can "identify" the class instance you want by as many ways
| you
|| > can
|| > | think of (as long as they are properly handled in you custom
|| > object.equals
|| > | method!).
|| > |
|| > |
|| > |
|| > | Anyway, that's it. The above is based on my experimentation and works
|| > fine
|| > | for me... I hope this will help anybody else that is having issues
| with
|| > the
|| > | arraylist.indexof functionality.
|| > |
|| > |
|| > |
|| > | John
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| >
|| >
||
||
|
|
Nov 21 '05 #17

P: n/a
John,
Here is an example based on Generics in VS.NET 2005. Plus some additional
info on non-delegate based Criteria.

Instead of a Delegates, you could define the Criteria as a "Query Object"
pattern. http://www.martinfowler.com/eaaCatalog/queryObject.html. I would
expect the delegate might be easier to implement, however the Query Object
might offer less coupling, especially if the Query Object was based on
reflection...
The "easiest" method to use a Generic Delegate is to start with
Collection(Of T). Collection(Of T) is the generic version of CollectionBase.
Something like:

' VS.NET 2005 syntax
Imports System.Collection.ObjectModel

Public Delegate Function Predicate(Of T, V)(ByVal item As T, ByVal value
As V) As Boolean

Public Class CollectionBase(Of T)
Inherits Collection(Of T)

Public Overloads Function IndexOf(Of V)(ByVal value As V, _
ByVal predicate As Predicate(Of T, V)) As Integer
For index As Integer = 0 To Me.Count - 1
If predicate(Me(index), value) Then
Return index
End If
Next
Return -1
End Function

Public Function Find(Of V)(ByVal value As V, _
ByVal predicate As Predicate(Of T, V)) As T
For Each item As T In Me
If predicate(item, value) Then
Return item
End If
Next
End Function

End Class

Public Class PersonCollection
Inherits CollectionBase(Of Person)

' yes its really empty!

End Class

Public Enum JobCategory
Category1 = 1
Category2 = 2
End Enum

Public Class Person

Public ReadOnly Name As String
Public ReadOnly JobCategory As String

Public Sub New(ByVal name As String, ByVal jobCategory As String)
Me.Name = name
Me.JobCategory = jobCategory
End Sub

Public Shared Function CompareName(ByVal item As Person, _
ByVal value As String ) As Boolean
Return item.Name = value
End Function

Public Shared Function CompareJobCategory(ByVal item As Person, _
ByVal value As JobCategory) As Boolean
Return item.JobCategory = value
End Function

End Class

Public Sub Main()
Dim people As New PersonCollection
people.Add(New Person("jay", JobCategory.Category2))
people.Add(New Person("john", JobCategory.Category1))

Dim index As Integer

index = people.IndexOf("jay", AddressOf Person.CompareName)
index = people.IndexOf(JobCategory.Category1, AddressOf
Person.CompareJobCategory)

Dim foundPerson As Person = people.Find("jay", AddressOf
Person.CompareName)

foundPerson = people.Find(JobCategory.Category2, AddressOf
Person.CompareJobCategory)
End Sub

Starting with Collection(Of T) also simplifies your type safe class as the
above shows.
Alternatively you could start with CollectionBase, however its not as clean
as the above (I actually implemented this sample first).

Public Class PersonCollection
Inherits CollectionBase

Default Public ReadOnly Property Item(ByVal index As Integer) As
Person
Get
Return DirectCast(Me.InnerList(index), Person)
End Get
End Property

Public Sub Add(ByVal person As Person)
Me.InnerList.Add(person)
End Sub

Public Function IndexOf(ByVal value As Object) As Integer
Return MyBase.InnerList.IndexOf(value)
End Function

Public Function IndexOf(Of V)(ByVal value As V, _
ByVal predicate As Predicate(Of Person, V)) As Integer
For index As Integer = 0 To Me.Count - 1
If predicate(Me.Item(index), value) Then
Return index
End If
Next
Return -1
End Function

Public Function Find(Of T, V)(ByVal value As V, _
ByVal predicate As Predicate(Of T, V)) As T
For Each item As T In Me.InnerList
If predicate(item, value) Then
Return item
End If
Next
End Function

End Class

Public Sub Main()
Dim people As New PersonCollection
people.Add(New Person("jay", JobCategory.Category2))
people.Add(New Person("john", JobCategory.Category1))

Dim index As Integer

index = people.IndexOf("jay", AddressOf Person.CompareName)
index = people.IndexOf(JobCategory.Category1, AddressOf
Person.CompareJobCategory)

Dim foundPerson As Person = people.Find(Of Person, String) _
("jay", AddressOf Person.CompareName)

foundPerson = people.Find(Of Person, JobCategory) _
(JobCategory.Category2, AddressOf Person.CompareJobCategory)

End Sub

Notice when calling Person.Find in the second example I had to supply the
type parameters, as they could not be inferred, in the first example, the
parameters were either supplied in the class itself "Inherits Collection(Of
Person)" or were easily inferred by the parameters to Find...

I would consider using the second method if I was migrating from an existing
VB.NET 2002 or VB.NET 2003 solution, until I was able to refactor the code
to use the first method...

Generics allow you to define types that have other types as parameters.

Hope this helps
Jay

"JohnR" <Jo******@hotmail.com> wrote in message
news:aRDce.1147$KP.566@trndny02...
| Hi Jay,
|
| I can appreciate your point of view... there are some good reasons to
| limit indexof to an apples to apples comparison. However, I'd like to
make
| my case as to why is can be valuable to have a more intelligent
| comparison.... and it's much more logical than, as you said, "comparing
| apples to auto parts". (now, why would anybody want to do that??)
|
| In our commercial application we have (so far) about 40 different custom
| classes which define the specific things the system will deal with. For
now
| lets say we have an Employee class, a Job category class, and an Employee
| Rating class.
| In our actual application virtually everything that is a custom class is
| stored in an arraylist so that it can be expanded at any time. In my
| example it means that you can start off with 15 job categories, and add 25
| more at a later date, without having to change 1 line of code. In some
| classes we set up an ENUM for ease and clarity of coding, and some ENUMs
| have 80 to 90 entries. To make matters more interesting, it is very
common
| that a class has a property that is another custom class. In the example
| you could imagine that an instance of the Employee class has a property
that
| is an instance of the JobCategory class.
| So the question (and it is a very serious question) is this: how can we
| easily code a retrieval process that will retrieve a specific instance of
a
| custom class that is stored in one of the arraylists.
| In different situations we may have different 'bits' of information to
| identify the instance we want. For example, we might want to search for a
| Job Category of "17" (that's it's unique job code) OR we may want to
search
| for a Job Category of "Teacher" (that's it's unique name). Either one is
| enough to uniquely identify the instance of the JobCategory class we are
| interested in. Now take this simple example and multiply it 100 fold and
| you begin to see why having a separate indexof for each possible way we
want
| to search would quickly get out of control.
| The solution we are using involves a derived arraylist that has overridden
| the indexof method. All of our class instances are stored in these custom
| arraylists. The indexof method will call the object.equals method as long
| as the arraylist is not empty.
| Each of the custom object.equals methods is pretty smart. They first test
| for type (ie: typeof xxx is string) and then test for whatever we need to
| match in the class properties to see if we actually have a match. This
| works very well.
| Now, the thing that makes it all come together is this: the function that
| actually searches these arraylists has an overload for each of the
different
| arraylist collections. This way, we positively know what we can search
on,
| and when the function returns the class instance, it returns it CAST AS
THE
| ACTUAL CLASS, so we can use the dot nomenclature to obtain any other
| property or access any other method of the class. The search function is
| called FINDITEM and here is an example of how it might work: Let's say
you
| want to find the number of sick days employee 12345 has had year to date:
|
| intNumSickDays = FINDITEM(alEmployeeCollection, new Employee,
| 12345).NumSickDays
|
| That's it. Pretty easy and straightforward. The first param is the
| arraylist collection, the second is just a instance of the custom class
| we're looking for (used to identify the proper overload), and the third
| param is what we're searching for. Notice that we are accessing the
| NumOfSickDays property DIRECTLY from the FindItem function. Better yet,
| since our custom classes can be nested (as the example above) this search
| function CAN ALSO BE NESTED! Complex, multilevel, searches through
| multiple arraylists with one easily understood statement. It doesn't get
| much better than that!
|
| We have estimated that by using this technique we will save hundreds of
| manhours in coding over the development of the project (think $$$), not to
| mention that our implimentation will be extremely extensible (everythings
| stored in arraylists, which can be expanded), and extremely reliable
| (basically one function to call to retrieve any data). The only downside
| to this would be performance. However, we made the decision to go with
the
| easy to use, bulletproof code because next year the computers will be
twice
| as fast as today anyway, so what the heck.
|
| Well, Jay, that's my case. Hope I've made a convincing one...
|
| John
|
|
|
|
|
|
|
| "Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
| news:Oj**************@TK2MSFTNGP15.phx.gbl...
| > John,
| > | 2) If you pass anything other than an instance of your custom class to
| > the
| > | indexof method (even if your object.equals code would know how to
handle
| > it)
| > | the indexof method will always return -1 (not found).
| > As I told Tom: I would expect that! As my understanding is that
| > Object.Equals should only succeed if both types are identical or at
least
| > derived types. The Point example on the link I gave earlier demonstrates
| > this "rule", however I don't see the "rule" spelled out...
| >
| > Even with Derived types there is risk involved will allowing the
| > comparison...
| >
| > | So what do you do if you have coded some intelligent object.equals
| > methods
| > | and want to take advantage of them?
| > Unfortunately your "intelligent object.equals", now is comparing apples
to
| > auto parts. Comparing apples to auto parts is not really logical
| > ("intelligent"). I can see comparing an Apple to an Orange, as they are
| > both
| > fruits. However! An Apple cannot be an Orange, only attributes of the
| > Apple
| > can be the same as attributes of the Orange, ergo you should be
comparing
| > the attributes of the Apple & Orange instead of attempting to compare
the
| > Apple & Orange directly!
| >
| > | Anyway, that's it. The above is based on my experimentation and works
| > fine
| > | for me... I hope this will help anybody else that is having issues
with
| > the
| > | arraylist.indexof functionality.
| > ArrayList.IndexOf seems to work as I would expect it to! As I showed in
my
| > sample earlier I don't allow my Object.Equals to compare objects of
| > different types, (Person <> String). If I needed to search the ArrayList
| > for
| > an object with a specific attribute I would define an alternate IndexOf
| > (with a specific name) that did the look up.
| >
| >
| > Public Function SearchForFirstName(name As String) As Integer
| > For i As Integer = 0 To Me.Count - 1
| > If Me.Item(i).FirstName = name Then
| > Return index
| > End If
| > Next
| > Return -1
| > End Function
| >
| > As its obvious that SearchForFirstName is searching for an object with a
| > specific first name.
| >
| > If the object supported implicit or explicit conversion between types
| > (current C# or VB.NET 2005 overloaded Widening or Narrowing CType
| > operators), such as a String can be widened to a Categoryobject. I would
| > do
| > this conversion before calling the IndexOf operator. Although there is a
| > conversion between String & Category, Category.Equals would still only
| > compare two Category values.
| >
| > Hope this helps
| > Jay
| >
| >
| > "JohnR" <Jo******@hotmail.com> wrote in message
| > news:Lq7ce.2139$pc7.327@trndny05...
| > | OK, first I want to thank all that contributed to this conversation.
| > after
| > | much experimenting I have (I think) narrowed down what is going on
| > | concerning the ARRAYLIST.INDEXOF functionality.
| > |
| > |
| > |
| > | 1) in a normal arraylist containing custom class instances, if you
pass
| > an
| > | instance of that custom class to the indexof method, it all works as
| > | expected.
| > |
| > | Example: x = arraylist.indexof(mycustomclass)
| > |
| > | Indeed, the overridden object.equals method in your custom class is
| > called
| > | as verified by a breakpoint in the code.
| > |
| > |
| > |
| > | 2) If you pass anything other than an instance of your custom class to
| > the
| > | indexof method (even if your object.equals code would know how to
handle
| > it)
| > | the indexof method will always return -1 (not found).
| > |
| > |
| > |
| > | Example: x = arraylist.indexof(integer) will always
| > return -1
| > |
| > |
| > |
| > | I'm guessing that the standard indexof method initially checks the
type
| > of
| > | the parameter and if it's not the same as the type contained in the
| > | arraylist it chooses not to continue by calling object.equals. it
just
| > | gives up and returns a -1. The standard indexof method knows that
the
| > | standard object.equals method expects an instance of the 'myclass'
class
| > and
| > | does not allow for the possibility that you have overridden the
| > | object.equals method with a more intelligent one.
| > |
| > |
| > |
| > | So what do you do if you have coded some intelligent object.equals
| > methods
| > | and want to take advantage of them?
| > |
| > | Example: indexof(myclass) or indexof("string") or
| > indexof(integer)
| > | could all
| > |
| > | work because my object.equals method tests for the 'typeof'
| > | parameter passed
| > |
| > | and would handle each case appropriately.
| > |
| > |
| > |
| > | What you need to do is create a custom Arraylist class (ie:
MyArraylist)
| > | which inherits Arraylist and overrides the indexof method as follows:
| > |
| > |
| > |
| > | Public Class MyArraylist
| > |
| > | Inherits ArrayList
| > |
| > | Public Overloads Overrides Function indexof(ByVal obj As
Object)
| > As
| > | Integer
| > |
| > | If Me.Count = 0 Then Return -1
| > |
| > | For i As Integer = 0 To Me.Count - 1
| > |
| > | If Me.Item(i).Equals(obj) Then
| > |
| > | Return i
| > |
| > | End If
| > |
| > | Next
| > |
| > | Return -1
| > |
| > | End Function
| > |
| > | End Class
| > |
| > |
| > |
| > | This overridden indexof method does not care about the type of the
| > parameter
| > | passed to it. As long as the arraylist is not empty (me.count >0) it
| > will
| > | call the object.equals method and you will get the results you expect.
| > | Using this custom arraylist for your collection of objects gives you a
| > | tremendous amount of flexibility and greatly simplifies application
code
| > | that you need to grab a particular class instance out of the
arraylist,
| > | since you can "identify" the class instance you want by as many ways
you
| > can
| > | think of (as long as they are properly handled in you custom
| > object.equals
| > | method!).
| > |
| > |
| > |
| > | Anyway, that's it. The above is based on my experimentation and works
| > fine
| > | for me... I hope this will help anybody else that is having issues
with
| > the
| > | arraylist.indexof functionality.
| > |
| > |
| > |
| > | John
| > |
| > |
| > |
| > |
| > |
| > |
| > |
| > |
| >
| >
|
|
Nov 21 '05 #18

P: n/a
Doh!

In the CollectionBase version of PersonCollection (the 2nd example) I can
simplify the Find function by declaring Person inline instead of defining
the T type parameter.

Instead of:

| Public Class PersonCollection
| Inherits CollectionBase

| Public Function Find(Of T, V)(ByVal value As V, _
| ByVal predicate As Predicate(Of T, V)) As T
| For Each item As T In Me.InnerList
| If predicate(item, value) Then
| Return item
| End If
| Next
| End Function

I should have used:

Public Function Find(Of V)(ByVal value As V, _
ByVal predicate As Predicate(Of Person, V)) As Person
For Each item As Person In Me.InnerList
If predicate(item, value) Then
Return item
End If
Next
End Function

| End Class

Which then allows you to call it without the type parameters (V is able to
be inferred).

Dim foundPerson As Person = people.Find _
("jay", AddressOf Person.CompareName)

Hope this helps
Jay

"Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
news:e$**************@TK2MSFTNGP14.phx.gbl...
| John,
| Here is an example based on Generics in VS.NET 2005. Plus some additional
| info on non-delegate based Criteria.
|
| Instead of a Delegates, you could define the Criteria as a "Query Object"
| pattern. http://www.martinfowler.com/eaaCatalog/queryObject.html. I would
| expect the delegate might be easier to implement, however the Query Object
| might offer less coupling, especially if the Query Object was based on
| reflection...
|
|
| The "easiest" method to use a Generic Delegate is to start with
| Collection(Of T). Collection(Of T) is the generic version of
CollectionBase.
| Something like:
|
| ' VS.NET 2005 syntax
| Imports System.Collection.ObjectModel
|
| Public Delegate Function Predicate(Of T, V)(ByVal item As T, ByVal
value
| As V) As Boolean
|
| Public Class CollectionBase(Of T)
| Inherits Collection(Of T)
|
| Public Overloads Function IndexOf(Of V)(ByVal value As V, _
| ByVal predicate As Predicate(Of T, V)) As Integer
| For index As Integer = 0 To Me.Count - 1
| If predicate(Me(index), value) Then
| Return index
| End If
| Next
| Return -1
| End Function
|
| Public Function Find(Of V)(ByVal value As V, _
| ByVal predicate As Predicate(Of T, V)) As T
| For Each item As T In Me
| If predicate(item, value) Then
| Return item
| End If
| Next
| End Function
|
| End Class
|
| Public Class PersonCollection
| Inherits CollectionBase(Of Person)
|
| ' yes its really empty!
|
| End Class
|
| Public Enum JobCategory
| Category1 = 1
| Category2 = 2
| End Enum
|
| Public Class Person
|
| Public ReadOnly Name As String
| Public ReadOnly JobCategory As String
|
| Public Sub New(ByVal name As String, ByVal jobCategory As String)
| Me.Name = name
| Me.JobCategory = jobCategory
| End Sub
|
| Public Shared Function CompareName(ByVal item As Person, _
| ByVal value As String ) As Boolean
| Return item.Name = value
| End Function
|
| Public Shared Function CompareJobCategory(ByVal item As Person, _
| ByVal value As JobCategory) As Boolean
| Return item.JobCategory = value
| End Function
|
| End Class
|
| Public Sub Main()
| Dim people As New PersonCollection
| people.Add(New Person("jay", JobCategory.Category2))
| people.Add(New Person("john", JobCategory.Category1))
|
| Dim index As Integer
|
| index = people.IndexOf("jay", AddressOf Person.CompareName)
| index = people.IndexOf(JobCategory.Category1, AddressOf
| Person.CompareJobCategory)
|
| Dim foundPerson As Person = people.Find("jay", AddressOf
| Person.CompareName)
|
| foundPerson = people.Find(JobCategory.Category2, AddressOf
| Person.CompareJobCategory)
| End Sub
|
| Starting with Collection(Of T) also simplifies your type safe class as the
| above shows.
|
|
| Alternatively you could start with CollectionBase, however its not as
clean
| as the above (I actually implemented this sample first).
|
| Public Class PersonCollection
| Inherits CollectionBase
|
| Default Public ReadOnly Property Item(ByVal index As Integer) As
| Person
| Get
| Return DirectCast(Me.InnerList(index), Person)
| End Get
| End Property
|
| Public Sub Add(ByVal person As Person)
| Me.InnerList.Add(person)
| End Sub
|
| Public Function IndexOf(ByVal value As Object) As Integer
| Return MyBase.InnerList.IndexOf(value)
| End Function
|
| Public Function IndexOf(Of V)(ByVal value As V, _
| ByVal predicate As Predicate(Of Person, V)) As Integer
| For index As Integer = 0 To Me.Count - 1
| If predicate(Me.Item(index), value) Then
| Return index
| End If
| Next
| Return -1
| End Function
|
| Public Function Find(Of T, V)(ByVal value As V, _
| ByVal predicate As Predicate(Of T, V)) As T
| For Each item As T In Me.InnerList
| If predicate(item, value) Then
| Return item
| End If
| Next
| End Function
|
| End Class
|
| Public Sub Main()
| Dim people As New PersonCollection
| people.Add(New Person("jay", JobCategory.Category2))
| people.Add(New Person("john", JobCategory.Category1))
|
| Dim index As Integer
|
| index = people.IndexOf("jay", AddressOf Person.CompareName)
| index = people.IndexOf(JobCategory.Category1, AddressOf
| Person.CompareJobCategory)
|
| Dim foundPerson As Person = people.Find(Of Person, String) _
| ("jay", AddressOf Person.CompareName)
|
| foundPerson = people.Find(Of Person, JobCategory) _
| (JobCategory.Category2, AddressOf
Person.CompareJobCategory)
|
| End Sub
|
| Notice when calling Person.Find in the second example I had to supply the
| type parameters, as they could not be inferred, in the first example, the
| parameters were either supplied in the class itself "Inherits
Collection(Of
| Person)" or were easily inferred by the parameters to Find...
|
| I would consider using the second method if I was migrating from an
existing
| VB.NET 2002 or VB.NET 2003 solution, until I was able to refactor the code
| to use the first method...
|
| Generics allow you to define types that have other types as parameters.
|
| Hope this helps
| Jay
|
| "JohnR" <Jo******@hotmail.com> wrote in message
| news:aRDce.1147$KP.566@trndny02...
|| Hi Jay,
||
|| I can appreciate your point of view... there are some good reasons to
|| limit indexof to an apples to apples comparison. However, I'd like to
| make
|| my case as to why is can be valuable to have a more intelligent
|| comparison.... and it's much more logical than, as you said, "comparing
|| apples to auto parts". (now, why would anybody want to do that??)
||
|| In our commercial application we have (so far) about 40 different custom
|| classes which define the specific things the system will deal with. For
| now
|| lets say we have an Employee class, a Job category class, and an Employee
|| Rating class.
|| In our actual application virtually everything that is a custom class is
|| stored in an arraylist so that it can be expanded at any time. In my
|| example it means that you can start off with 15 job categories, and add
25
|| more at a later date, without having to change 1 line of code. In some
|| classes we set up an ENUM for ease and clarity of coding, and some ENUMs
|| have 80 to 90 entries. To make matters more interesting, it is very
| common
|| that a class has a property that is another custom class. In the example
|| you could imagine that an instance of the Employee class has a property
| that
|| is an instance of the JobCategory class.
|| So the question (and it is a very serious question) is this: how can we
|| easily code a retrieval process that will retrieve a specific instance of
| a
|| custom class that is stored in one of the arraylists.
|| In different situations we may have different 'bits' of information to
|| identify the instance we want. For example, we might want to search for
a
|| Job Category of "17" (that's it's unique job code) OR we may want to
| search
|| for a Job Category of "Teacher" (that's it's unique name). Either one
is
|| enough to uniquely identify the instance of the JobCategory class we are
|| interested in. Now take this simple example and multiply it 100 fold
and
|| you begin to see why having a separate indexof for each possible way we
| want
|| to search would quickly get out of control.
|| The solution we are using involves a derived arraylist that has
overridden
|| the indexof method. All of our class instances are stored in these
custom
|| arraylists. The indexof method will call the object.equals method as
long
|| as the arraylist is not empty.
|| Each of the custom object.equals methods is pretty smart. They first
test
|| for type (ie: typeof xxx is string) and then test for whatever we need to
|| match in the class properties to see if we actually have a match. This
|| works very well.
|| Now, the thing that makes it all come together is this: the function
that
|| actually searches these arraylists has an overload for each of the
| different
|| arraylist collections. This way, we positively know what we can search
| on,
|| and when the function returns the class instance, it returns it CAST AS
| THE
|| ACTUAL CLASS, so we can use the dot nomenclature to obtain any other
|| property or access any other method of the class. The search function is
|| called FINDITEM and here is an example of how it might work: Let's say
| you
|| want to find the number of sick days employee 12345 has had year to date:
||
|| intNumSickDays = FINDITEM(alEmployeeCollection, new Employee,
|| 12345).NumSickDays
||
|| That's it. Pretty easy and straightforward. The first param is the
|| arraylist collection, the second is just a instance of the custom class
|| we're looking for (used to identify the proper overload), and the third
|| param is what we're searching for. Notice that we are accessing the
|| NumOfSickDays property DIRECTLY from the FindItem function. Better yet,
|| since our custom classes can be nested (as the example above) this search
|| function CAN ALSO BE NESTED! Complex, multilevel, searches through
|| multiple arraylists with one easily understood statement. It doesn't get
|| much better than that!
||
|| We have estimated that by using this technique we will save hundreds of
|| manhours in coding over the development of the project (think $$$), not
to
|| mention that our implimentation will be extremely extensible (everythings
|| stored in arraylists, which can be expanded), and extremely reliable
|| (basically one function to call to retrieve any data). The only
downside
|| to this would be performance. However, we made the decision to go with
| the
|| easy to use, bulletproof code because next year the computers will be
| twice
|| as fast as today anyway, so what the heck.
||
|| Well, Jay, that's my case. Hope I've made a convincing one...
||
|| John
||
||
||
||
||
||
||
|| "Jay B. Harlow [MVP - Outlook]" <Ja************@msn.com> wrote in message
|| news:Oj**************@TK2MSFTNGP15.phx.gbl...
|| > John,
|| > | 2) If you pass anything other than an instance of your custom class
to
|| > the
|| > | indexof method (even if your object.equals code would know how to
| handle
|| > it)
|| > | the indexof method will always return -1 (not found).
|| > As I told Tom: I would expect that! As my understanding is that
|| > Object.Equals should only succeed if both types are identical or at
| least
|| > derived types. The Point example on the link I gave earlier
demonstrates
|| > this "rule", however I don't see the "rule" spelled out...
|| >
|| > Even with Derived types there is risk involved will allowing the
|| > comparison...
|| >
|| > | So what do you do if you have coded some intelligent object.equals
|| > methods
|| > | and want to take advantage of them?
|| > Unfortunately your "intelligent object.equals", now is comparing apples
| to
|| > auto parts. Comparing apples to auto parts is not really logical
|| > ("intelligent"). I can see comparing an Apple to an Orange, as they are
|| > both
|| > fruits. However! An Apple cannot be an Orange, only attributes of the
|| > Apple
|| > can be the same as attributes of the Orange, ergo you should be
| comparing
|| > the attributes of the Apple & Orange instead of attempting to compare
| the
|| > Apple & Orange directly!
|| >
|| > | Anyway, that's it. The above is based on my experimentation and works
|| > fine
|| > | for me... I hope this will help anybody else that is having issues
| with
|| > the
|| > | arraylist.indexof functionality.
|| > ArrayList.IndexOf seems to work as I would expect it to! As I showed in
| my
|| > sample earlier I don't allow my Object.Equals to compare objects of
|| > different types, (Person <> String). If I needed to search the
ArrayList
|| > for
|| > an object with a specific attribute I would define an alternate IndexOf
|| > (with a specific name) that did the look up.
|| >
|| >
|| > Public Function SearchForFirstName(name As String) As Integer
|| > For i As Integer = 0 To Me.Count - 1
|| > If Me.Item(i).FirstName = name Then
|| > Return index
|| > End If
|| > Next
|| > Return -1
|| > End Function
|| >
|| > As its obvious that SearchForFirstName is searching for an object with
a
|| > specific first name.
|| >
|| > If the object supported implicit or explicit conversion between types
|| > (current C# or VB.NET 2005 overloaded Widening or Narrowing CType
|| > operators), such as a String can be widened to a Categoryobject. I
would
|| > do
|| > this conversion before calling the IndexOf operator. Although there is
a
|| > conversion between String & Category, Category.Equals would still only
|| > compare two Category values.
|| >
|| > Hope this helps
|| > Jay
|| >
|| >
|| > "JohnR" <Jo******@hotmail.com> wrote in message
|| > news:Lq7ce.2139$pc7.327@trndny05...
|| > | OK, first I want to thank all that contributed to this conversation.
|| > after
|| > | much experimenting I have (I think) narrowed down what is going on
|| > | concerning the ARRAYLIST.INDEXOF functionality.
|| > |
|| > |
|| > |
|| > | 1) in a normal arraylist containing custom class instances, if you
| pass
|| > an
|| > | instance of that custom class to the indexof method, it all works as
|| > | expected.
|| > |
|| > | Example: x = arraylist.indexof(mycustomclass)
|| > |
|| > | Indeed, the overridden object.equals method in your custom class is
|| > called
|| > | as verified by a breakpoint in the code.
|| > |
|| > |
|| > |
|| > | 2) If you pass anything other than an instance of your custom class
to
|| > the
|| > | indexof method (even if your object.equals code would know how to
| handle
|| > it)
|| > | the indexof method will always return -1 (not found).
|| > |
|| > |
|| > |
|| > | Example: x = arraylist.indexof(integer) will always
|| > return -1
|| > |
|| > |
|| > |
|| > | I'm guessing that the standard indexof method initially checks the
| type
|| > of
|| > | the parameter and if it's not the same as the type contained in the
|| > | arraylist it chooses not to continue by calling object.equals. it
| just
|| > | gives up and returns a -1. The standard indexof method knows that
| the
|| > | standard object.equals method expects an instance of the 'myclass'
| class
|| > and
|| > | does not allow for the possibility that you have overridden the
|| > | object.equals method with a more intelligent one.
|| > |
|| > |
|| > |
|| > | So what do you do if you have coded some intelligent object.equals
|| > methods
|| > | and want to take advantage of them?
|| > |
|| > | Example: indexof(myclass) or indexof("string") or
|| > indexof(integer)
|| > | could all
|| > |
|| > | work because my object.equals method tests for the 'typeof'
|| > | parameter passed
|| > |
|| > | and would handle each case appropriately.
|| > |
|| > |
|| > |
|| > | What you need to do is create a custom Arraylist class (ie:
| MyArraylist)
|| > | which inherits Arraylist and overrides the indexof method as follows:
|| > |
|| > |
|| > |
|| > | Public Class MyArraylist
|| > |
|| > | Inherits ArrayList
|| > |
|| > | Public Overloads Overrides Function indexof(ByVal obj As
| Object)
|| > As
|| > | Integer
|| > |
|| > | If Me.Count = 0 Then Return -1
|| > |
|| > | For i As Integer = 0 To Me.Count - 1
|| > |
|| > | If Me.Item(i).Equals(obj) Then
|| > |
|| > | Return i
|| > |
|| > | End If
|| > |
|| > | Next
|| > |
|| > | Return -1
|| > |
|| > | End Function
|| > |
|| > | End Class
|| > |
|| > |
|| > |
|| > | This overridden indexof method does not care about the type of the
|| > parameter
|| > | passed to it. As long as the arraylist is not empty (me.count >0) it
|| > will
|| > | call the object.equals method and you will get the results you
expect.
|| > | Using this custom arraylist for your collection of objects gives you
a
|| > | tremendous amount of flexibility and greatly simplifies application
| code
|| > | that you need to grab a particular class instance out of the
| arraylist,
|| > | since you can "identify" the class instance you want by as many ways
| you
|| > can
|| > | think of (as long as they are properly handled in you custom
|| > object.equals
|| > | method!).
|| > |
|| > |
|| > |
|| > | Anyway, that's it. The above is based on my experimentation and works
|| > fine
|| > | for me... I hope this will help anybody else that is having issues
| with
|| > the
|| > | arraylist.indexof functionality.
|| > |
|| > |
|| > |
|| > | John
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| > |
|| >
|| >
||
||
|
|
Nov 21 '05 #19

This discussion thread is closed

Replies have been disabled for this discussion.