Comparing Reference Types


Comparing reference types is different than comparing numeric types. Reference types are variables that point to objects created as the result of using new on class type (for example: Account acct = new Account() where Account is a class definition). The reason it is different is that numeric types are allocated differently in memory than reference types. Whenever you use a variable that is a numeric type, the variable represents an address in memory where the value is stored. A variable that points to a reference type doesn't point to the object directly. Instead, it points to the place in memory that stores the address of the object ( Figure 3.7 ).

Figure 3.7. A variable that is a value type (numeric types, bool, char, etc.) points to the actual data in memory. Reference type variables on the other hand point to an address which then points to the object.

graphics/03fig07.gif

Since a reference type points to an address that points to an object and not to the object directly there are two questions we can ask when comparing two reference variables: are the two variables pointing to the same object, and if they aren't, are the two objects referring to the same thing? For example if we are comparing two Account variables we can first ask: Are the two variables referring to the same object in memory? Then we can ask: If they aren't the same object, are they the same account, i.e. both have the same account number and the same balance? The first question (same object) is a question of identity, the second question (same data in the object) is a question of equivalence ( Figure 3.8 ).

Figure 3.8. With reference types, two questions are important. Are the variables pointing to the same object in memory? If not, do the object's fields contain the same information? In the figure you see that acct1 and acct2 point to the same object, while acct3 and acct4 point to different objects but refer to the same information.

graphics/03fig08.gif

To compare two reference variables for identity:

  • Type bool bResult = object.ReferenceEquals(var1,var2); where var1 and var2 are the two reference variables to compare ( Figure 3.9 ).

    Figure 3.9 Even though the data for the fields is the same in p1 and p2, ReferenceEquals only tests whether the variables are pointing to the same memory address. They aren't because we are creating two distinct objects.
     class Person {    public string LastName;    public string FirstName; } class App {    void DoTask1()    {      Person p1 = new Person();      p1.LastName = "Mojica";      p1.FirstName = "Jose";      Person p2 = new Person();      p2.LastName = "Mojica";      p2.FirstName = "Jose";      Person p3 = p2;      bool bResult1 = object.  ReferenceEquals  (                            p1,p2); //false      bool bResult2 = object.  ReferenceEquals  (                            p2,p3); //true    } } 

    or

  • Type bool bResult = (var1 == var2) where var1 and var2 are the two reference variables to compare.

To compare two reference variables for equivalence:

  • Type bool bResult = var1.Equals(var2); or bool bResult = var2.Equals(var1); where var1 and var2 are the two reference variables to compare.

    or

  • Type bool bResult = (var1 == var2) where var1 and var2 are the two reference variables to compare ( Figure 3.10 ).

    Figure 3.10 The result statements are only true if the developer of the Person class overrides the default implementation of Equals and the default implementation of the == operator. Both Equals and == are intended to be for equivalence, but without the programmer implementing the methods the results are based on identity. You will learn how to override Equals and == in Chapter 7, "Types."
     class Person {    public string LastName;    public string FirstName;    public override bool Equals(    object obj)    {      //implementation discussed in a      //later chapter    }    public static bool operator ==(    Person p1, Person p2)    {       return p1.Equals(p2);    }    public static bool operator !=(    Person p1, Person p2)    {       return !(p1==p2);    } } class App {    void DoTask1()    {       Person p1 = new Person();       p1.LastName = "Mojica";       p1.FirstName = "Jose";       Person p2 = new Person();       p2.LastName = "Mojica";       p2.FirstName = "Jose";       Person p3 = p2;       //true       bool bResult1 = p1.  Equals  (p2);       //true       bool bResult2 = p2.  Equals  (p3);       //true        bool bResult3 = (p2  ==  p3);    } } 

graphics/tick.gif Tips

  • Testing for identity is faster than testing for equivalence. Although no developer does this consistently, it makes sense to do a test for identity before doing a test for equivalence. That way, you eliminate the need for an equivalence test if the two variables are pointing to the same object. For that reason a developer who redefines the == sign should perform an identity check first and return true immediately if the two things compared are exactly the same object.

  • OK what gives? If you look at both the test for identity and the test for equivalence, in both cases I've said that you can use the == operator. So is == for identity or for equivalence? The answer: it's for both. By default, whenever you use the == operator the compiler writes code to do an identity check. However, a developer may override the way that == works as you will see in Chapter 7, "Types." Most of the time when developers use the == operator with reference types they're looking for the program to perform a test of equivalence.

  • Strings are a special kind of reference types that support comparisons with the == and != operators. For details, see Chapter 4, "Strings" ( Figure 3.11 ).

    Figure 3.11 Strings override the == operator as well as the != operator. When you compare two strings with == you are comparing the contents of the string, not whether the two variables point to the same string object. Unfortunately you can't use the < or > operators with strings.
     class Person {    public string LastName;    public string FirstName; } class App {    void DoTask1()    {       Person p1 = new Person();       p1.LastName = "Mojica";       Person p2 = new Person();       p2.LastName = "Mojica";       bool Same = (  p1.LastName ==   p2.LastName  ); //true       p1.LastName = "Smith";       bool Before = (  p1.LastName <   p2.LastName  );       //*** Error < operator not       //supported    } } 
  • In addition to using == you can use != to test for two things not being equal. If a developer redefines the == then the compiler forces the developer to also override the != operator. Thus if the == performs an equivalence test, the != will also. A common practice is to perform a test for != null ( Figure 3.12 ).

    Figure 3.12 Be careful to test for null. A classic example is when you attempt to retrieve an item from the Session object. If the item is not found, the result is null.
     class App {    void ContactFamily()    {      Person brother =      (Person)Session["jarvx"];      if (  brother != null  )         WriteLetter(brother);    } } 



C#
C# & VB.NET Conversion Pocket Reference
ISBN: 0596003196
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Jose Mojica

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net