Link to home
Start Free TrialLog in
Avatar of FaithNoMore
FaithNoMore

asked on

VB.NET ArrayList.contains(...) Do this not use the "Equals(ByVal obj as Object)" Method????

Ok, I am extremely confused here :)  I come from a strong Java background (by strong, I mean I have a good understanding on how java works as a OOP language), and recently I have been learning how to use the .NET framework.  I am currently having problems with ArrayList Class, specifically the "Public Function Contains(ByVal value As Object) As Boolean".  

Here are parts of my current code.

in my Name Class:

 ' I am assuming this overrides the System.Object.Equals method.... if
'  it doesnt, than this is probably my problem :)

 '  Below is the code for the Name Class.  Which is in the same code 'file' as another class.. I dont
 '  think this makes a difference, but am mentioning it encase.

Public Class MyOtherClass

.... ' Other class data and methods...etc

End Class

Public Class Name
    Private First As String
    Private Last As String

    Public Sub New(ByVal First As String, ByVal Last As String)
        Firstname = First
        Lastname = Last
    End Sub

    Public Overloads Function ToString() As String
        Return Me.Last & ", " & Me.Last
    End Function

    Public Overloads Function Equals(ByVal obj As Object) As Boolean

        Dim name As Name

'  Ignoring types until I can get this part working....
'  In my test, I have ONLY sent Name objects to this method.

        name = CType(obj, Name)
        If Me.First.ToLower.Equals(name.First.ToLower) And _
           Me.Last.ToLower.Equals(name.Last.ToLower) Then
            Return True
            '  End If
        End If
        Return False
    End Function


    Public Property Firstname() As String
        Get
            Firstname = First
        End Get
        Set(ByVal Value As String)
            If Value.Equals("") Then
                Throw New MySql.MySqlException("Please Enter a valid firstname!")
            End If
            First = Value
        End Set
    End Property

    Public Property Lastname() As String
        Get
            Lastname = Last
        End Get
        Set(ByVal Value As String)
            If Value.Equals("") Then
                Throw New MySql.MySqlException("Please Enter a valid lastname!")
            End If
            Last = Value
        End Set
    End Property

End Class


'  Now in another file I have a form that has an variable:

Public myNames as Arraylist

....and here is part of that form class

'  I click on a button and it calls this function,  however, it NEVER returns true for the expression
    Private Sub addName(ByVal obj As Name)
        ' Adds the name to the mynames arraylist

        If myNames.Contains(obj) Then
            Throw New MySql.MySqlException("Name already exists in the list!")
        End If
        myNames.Add(obj)   ' Adds object to the list
        Call refreshList()       ' refreshins certain feilds.
    End Sub



I can add the same name over and over again, and whenever I use the .contains function, it never returns true....  I am either missing something very basic with how .net uses the equals method or I am missing something very simple in my own code, either way I am fed up.....so here I am.  I've also had a few drinks since I have started tonight, that could be the reason too :)
Avatar of _TAD_
_TAD_

Here is your problem...

 Private Sub addName(ByVal obj As Name)
        ' Adds the name to the mynames arraylist



.Net's Equals() and Contains() methods do NOT check the values or the contents of the objects.

Nay, they checks the objects guid/refernce number and checks to see if that that serial number appears in your list.   When you specify "ByVal" .net takes the VALUE of your object and creates a NEW object (with a new serial number/guid).


Soooo.....

Object 124-345a-3456-24 with a value of "This is string 1"

DOES NOT EQUAL

Object 876-234a-7644-11 with a value of "This is string 1"



I think you'll want to do a  ByRef call instead of byval, or perhaps do an Object.Copy()



Avatar of FaithNoMore

ASKER

I've changed my addName and removeName methods to use ByRef, but it doesnt seem to make a difference.  

When I do a ArrayList.contains() methods, how does it determine if the arraylist contains my specified object?  The .NET documentation says it uses the Equals method...I am assuming its the equals method of the object, but it doesnt seem to use my equals method at all.

Also, when I make an instance of a Name object, and look at the available methods, it shows my Equals method that takes two parameters, and the Equals method that I made (it says Overrides).  Am I overriding the wrong equals method?



Take a peek at this code:



                  //Variable Declaration
                  char[] c;
                  string str1;
                  string str2;
                  object obj1;
                  object obj2;
                  ArrayList list = new ArrayList();

                  // Create New Char array
                  c = "String1".ToCharArray();  

                  //Create a new string with a value of "String1"
                  str1 = new string(c);  
                  //Create a new string with a value of "String1"
                  str2 = new string(c);  

                  // Create a new object with a reference to str1
                  obj1 = (object)str1;  
                  // Create a new object with a reference to str2
                  obj2 = (object)str2;  
            
                  //Add a string object to an array list with a value of "String1"
                  list.Add(new string(c));

                  // display the hash value of obj1->str1
                  Console.WriteLine("HashCode of obj1: {0}",obj1.GetHashCode().ToString());  
                  // display the hash value of obj2->str2
                  Console.WriteLine("HashCode of obj1: {0}", obj2.GetHashCode().ToString());  

                  //display GUID.Equals call for obj1 and obj2
                  Console.WriteLine("Are the system objects equal(GUID.Equals(obj1,obj2): {0}", Guid.Equals(obj1,obj2).ToString());
                  //display GUID.ReferenceEquals call for obj1 and obj2
                  Console.WriteLine("Are the system objects the same instance (GUID.ReferenceEquals(obj1,obj2): {0}", Guid.ReferenceEquals(obj1,obj2).ToString());

                  // References should NOT be equal, they are two different values
                  Console.WriteLine("Static ReferenceEquals() call, compares ref obj1 to ref obj2: {0}",ReferenceEquals(obj1, obj2).ToString());  

                  // Values should be equal, they all obtain their values from the same source
                  Console.WriteLine("Static Equals() call, compares obj1 to obj2: {0}", Equals(obj1, obj2).ToString());
                  // Values should be equal, they all obtain their values from the same source Static Vs. Instance should make no difference
                  Console.WriteLine("Instance Equals() call, compares obj2 to obj1: {0}",obj1.Equals(obj2).ToString());

                  // Check to see if array list contains the values of the object in question
                  Console.WriteLine("Array List Contains obj1: {0}",list.Contains(obj1).ToString());  
                  





Here are the results I got:


HashCode of obj1: -2105404575
HashCode of obj1: -2105404575

Are the system objects equal(GUID.Equals(obj1,obj2): True
Are the system objects the same instance (GUID.ReferenceEquals(obj1,obj2): False

Static ReferenceEquals() call, compares ref obj1 to ref obj2: False

Static Equals() call, compares obj1 to obj2: True
Instance Equals() call, compares obj2 to obj1: True

Array List Contains obj1: True




>When I do a ArrayList.contains() methods, how does it determine if the arraylist contains my specified object?  The .NET >documentation says it uses the Equals method...I am assuming its the equals method of the object, but it doesnt seem to >use my equals method at all.


Actually, it does NOT use the instance Equals method call, it uses the STATIC equals() method call.  The reason for this is an added level of saftey.  

If your object is Null, then the instance level equals call will throw an error, the static call actualls handles null values.


Bool b = System.Equals(null, null);
// b = true

bool b = obj1.Equals(null);
// b = false  --or-- if obj1 is null, will throw an error.   obj1 cannot be null for this to work




The Equals() method is used to test for reference equality.  Derived value-type calsses must override this method to provide a value equality (so you can return true for identicle content even if the values are stored in different objects and different memory locations).

The ReferenceEquals method compares the object's Identity rather than its contents.


Because you are trying to compare the contents of two objects you will have to override the Equals() method on each instance.  However, you are also trying to use the ArrayList.Contains() method which uses the Static Version of the Equals(obj1, obj2) method.


What you may have to do is itterate through your arrayList and determine if any of the elements are equal to your object.


Public bool Contains(byRef object obj1, byRef ArrayList list1)
{
   // this method uses your overriden EQUALS() method to compare values

   bool contains = false;
   for(int i=0; i<list1.count; i++)
       if(obj1.Equals(list1[i])
       {
            contains = true;
            break;
       }

   return contains;
}
Ok, I think I understand how this all works now.  the ArrayList.contains(obj as Object ) and Arraylist.remove(obj as Object) doesn't use

- Public Overloads Shared Function ReferenceEquals(ByVal objA As Object, ByVal objB As Object) As Boolean

- Public Overloads Function Equals(ByVal obj As Object) As Boolean

- Public Overloads Shared Function Equals(ByVal objA As Object, ByVal objB As Object) As Boolean



Now, is it possible for me to override the 'static' equals method?  It would be easier if I didnt have to make two methods (one to remove objects and one to find equal objects in my Arraylist) when I could just use the contains and remove methods from Arraylist itself.  Also I havent found any reference to this 'static' method, what class does it come from?
ASKER CERTIFIED SOLUTION
Avatar of _TAD_
_TAD_

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
What finally worked was this:

Overloads Overrides Function Equals(ByVal obj As Object) As Boolean

Just a little syntax mistake, guess I had to overload and override the method.. Learn something new everyday~ :)