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
[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
                > - 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" <larr...@hotmail.com> wrote in message 
news:1114511373.8...@f14g2000cwb.googlegroups.com...
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 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" <larr...@hotmail.com> wrote in message 
news:1114527820.9...@z14g2000cwz.googlegroups.com...
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" <John...@hotmail.com> wrote in message 
news:HRkbe.5251$WX.1041@trndny01...
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" <larr...@hotmail.com> wrote in message 
news:1114511373.8...@f14g2000cwb.googlegroups.com...
|
So it does. Guess I should have checked that before going off on one,
to avoid looking silly now. Oh well.
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]
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!
Hope this helps
Jay
"Tom Shelton" <t...@YOUKNOWTHEDRILLmtogden.com> wrote in message 
news:uzQ2X1qS...@TK2MSFTNGP14.phx.gbl...
You're correct... His code does work as written.  I failed to look at it
closely before responding.  To quick on the draw :)
>| 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/default.asp?url=/library/en-us/cpref/html/frlrfsystemobjectclassequalstopic1.asp
>
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:
Dim x As New TheClass
Dim y As String = somevalue
x.Equals (y) <> y.Equals (x)
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.
-- 
Tom Shelton [MVP]
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/default.asp?url=/library/en-us/cpgenref/html/cpconEquals.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.
NOTE: I normally overload Equals to have both Equals(Object) & 
Equals(MyType) in the MyType type. My Equals(Object) normally calls 
Equals(MyType). Something like:
Public Class Person
        Private Readonly m_name As String
        Private Readonly m_id As String
        Public Overloads Overrides Function Equals(obj As Object) As Boolean
            If TypeOf obj Is Person Then
                Return Equals(DirectCast(obj, Person))
            Else
                Return False
            End If
        End Function
        Public Overloads Function Equals(other As Person) As Boolean
            Return m_name = other.m_name AndAlso m_id = other.m_id 
AndAlso...
        End Function
End Class
Hope this helps
Jay
"Tom Shelton" <tshe...@YOUKNOWTHEDRILLcomcast.net> wrote in message 
news:O%23%23aNSuS...@TK2MSFTNGP10.phx.gbl...
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]
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
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" <John...@hotmail.com> wrote in message 
news:Lq7ce.2139$pc7.327@trndny05...
   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]" <Jay_Har...@msn.com> wrote in message 
news:OjiFKjMT...@TK2MSFTNGP15.phx.gbl...
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/d9hy2xwa(en-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/ppbook/extracts/coincidence.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)".
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/replaceConditionalWithPolymorphism.html
Hope this helps
Jay
Hope this helps
Jay
"JohnR" <John...@hotmail.com> wrote in message 
news:aRDce.1147$KP.566@trndny02...
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]" <Jay_Har...@msn.com> wrote in message 
news:uSLuA6Z...@tk2msftngp13.phx.gbl...
|        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]" <Jay_Har...@msn.com> wrote in message 
news:uSLuA6Z...@tk2msftngp13.phx.gbl...
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" <John...@hotmail.com> wrote in message 
news:aRDce.1147$KP.566@trndny02...
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]" <Jay_Har...@msn.com> wrote in message 
news:e$Z2MgbTF...@TK2MSFTNGP14.phx.gbl...