JohnR,
| All through this forum we see
| questions about people overriding the Equals method of a custom class only
| to find that the ArrayList.Indexof method calls the Object.Equals method
and
| not their overridden Equals method.
As Mattias suggests, and I believe we have discussed before Object.Equals is
overridable! If you *override* Object.Equals in your derived class (not
ArrayList). ArrayList.IndexOf will polymorphically call the "correct" equal
method, something like:
Public Class Thingamajig
Private ReadOnly m_value1 As String
Private ReadOnly m_value2 As Integer
Public Sub New(ByVal value1 As String, ByVal value2 As Integer)
m_value1 = value1
m_value2 = value2
End Sub
Public Overloads Function Equals(ByVal other As Thingamajig) As
Boolean
Return m_value1 = other.m_value1 AndAlso m_value2 =
other.m_value2
End Function
Public Overloads Overrides Function Equals(ByVal obj As Object) As
Boolean
If TypeOf obj Is Thingamajig Then
Return Equals(DirectCast(obj, Thingamajig))
Else
Return False
End If
End Function
End Class
Public Shared Sub Main()
Dim list As New ArrayList
list.Add(New Thingamajig("jay", 1))
list.Add(New Thingamajig("jay", 2))
list.Add(New Thingamajig("jay", 3))
list.Add(New Thingamajig("JohnR", 1))
list.Add(New Thingamajig("JohnR", 2))
list.Add(New Thingamajig("JohnR", 3))
Dim index As Integer = list.IndexOf(New Thingamajig("JohnR", 2))
End Sub
| Public Shadows Function indexof(ByVal obj As Object) As Integer
Shadows is anti-polymorphic!
Anti-polymorphic code normally causes more problems then it helps.
You need to *Override* IndexOf instead, something like:
| Public Overloads Overrides Function indexof(ByVal obj As Object) As
Integer
Overloads is needed here as IndexOf is overloaded (see below).
| 'this will cause indexof to do a case insensitive search if obj
| 'is a string
I would use a Case Insensitive Comparer, such as
System.Collections.CaseInsensitiveComparer.Default or DeafultInvariant
instead, something like:
Public Class ArrayList
Inherits System.collections.ArrayList
Public Overloads Overrides Function IndexOf(ByVal value As Object)
As Integer
Return IndexOf(value, 0, Me.Count)
End Function
Public Overloads Overrides Function IndexOf(ByVal value As Object,
ByVal startIndex As Integer) As Integer
Return IndexOf(value, startIndex, Me.Count - startIndex)
End Function
Public Overloads Overrides Function IndexOf(ByVal value As Object,
ByVal startIndex As Integer, ByVal count As Integer) As Integer
Dim comparer As IComparer =
CaseInsensitiveComparer.DefaultInvariant
For index As Integer = startIndex To startIndex + count - 1
If comparer.Compare(Me(index), value) = 0 Then
Return index
End If
Next
Return -1
End Function
End Class
The CaseInsensitiveComparer object knows how to do case insensitive
comparisons of strings & comparisons of other types (such as integers).
--
Hope this helps
Jay
T.S. Bradley -
http://www.tsbradley.net
| Thanks to all the replys... I understand that, at first glance, what I am
| asking for doesn't make sense, but, it really does... I always start out
| with the stating the problem as directly as possible without unnecessary
| info, but since you all are asking "why in the world would you want to do
| that?" here is why:
|
| I am trying to write a new ArrayList class which will have (at least for
my
| application) a better IndexOf method. All through this forum we see
| questions about people overriding the Equals method of a custom class only
| to find that the ArrayList.Indexof method calls the Object.Equals method
and
| not their overridden Equals method. My goal was to remedy this situation.
| In addition, I wanted to have IndexOf to do a case insensitive search if
the
| obj is of type 'string'. Here is the class def'n:
|
| Public Class arraylist
| Inherits System.collections.ArrayList
| Public Shadows Function indexof(ByVal obj As Object) As Integer
|
| 'this will cause indexof to do a case insensitive search if obj
| 'is a string
| If TypeOf obj Is String Then
| For ptr As Integer = 0 To Me.Count - 1
| If CType(Me(ptr), String).ToUpper = CType(obj,
| String).ToUpper Then
| Return ptr
| End If
| Next
| Return -1
| Else
| For ptr As Integer = 0 To Me.Count - 1
|
| 'the next commented line won't work because it
| 'will call the object.equals method and NOT the
| 'overridden equals method of the class that is
| 'passed as the obj parameter
|
| 'If Me(ptr).equals(obj) Then
|
| 'However, let's say obj is of type "MyOwnClass" then
| 'the following WILL work because it will call the
| 'equals method that is defined in the MyOwnClass class.
|
| If CType(Me(ptr), MyOwnClass).equals(obj) Then
| Return ptr
| End If
|
| 'taking this to the ultimate solution, I would have
| 'liked to do something like this:
| 'If Ctype(Me(ptr), Me(ptr).gettype.name).equals(obj) Then
|
| Next
| Return -1
| End If
|
| End Function
| End Class
|
| So you see, I only need to cast the type onto whatever is contained in the
| obj so that it calls the proper Equals method. That's it. That's the
only
| reason I need to do this. I'm not going to mess with the obj in any other
| way so I'm not worried about "bugs" that may be introduced by screwing
with
| variable types at runtime.
| Clearly the alternative (and what I'm actually doing now) is testing the
| type of obj for each of my custom classes, and doing a manual cast once I
| find out what type it is. Very tacky, but it does work. I'm looking for
a
| more elegant, general solution here.
|
| John
|
| | > | >> I'm trying to find a way to create a variable of a given type at
runtime
| >> where I won't know the type until it actually executes.
| >
| > I would suggest that this is /possible/, but definitely not something
| > I would recommend - unless you *love* trying to sort out wierd
| > and wonderful Run-Time errors.
| >
| > .Net is an odd mix of [what we used to call] Early and Late binding.
| > At compile time, it's "Early Bound", using strict Types for everything,
| > which means that you /have/ to know the Type of something before
| > you can compile code to do anything with it. Objects are nowhere
| > as useful as Variants used to be.
| > At run-time, though, .Net seems to fall back on something more akin
| > to "Late Binding", loading methods as and when it needs them.
| >
| >> dim x as object = "hi"
| >>
| >> x is declared as an object but x.gettype returns 'string', so it knows
it
| >> contains a string.
| >
| > True.
| >
| >> If I want to create a variable "y" as the same type that variable x
| >> contains
| >
| > If you don't know the Type of "x" to start with, how do you intend to
| > manipulate "y", whose Type you have to know before you can access
| > its properties and methods?
| >
| > It boils down to having to know something about a class before you
| > can do anything with it.
| >
| >> how would I do that without having to iterate thru every possible
| >> type?
| >
| > You /could/ use Activator.CreateInstance, but it takes as one of
| > its arguments the Type of object you want to create ...
| >
| > HTH,
| > Phill W.
| >
| >
|
|