System.Object: The Ultimate Base Class

   


System.Object: The Ultimate Base Class

The .NET Framework class library contains a class called System.Object from which all classes are ultimately derived. This is due to two facts. First, whenever you create a class without specifying a base class for it, C# automatically specifies System.Object to be its base class. Second, any chain of derived classes will always have a topmost class (like TransportVehicle in Figure 16.9 of Chapter 16) that does not have any base class specified. This topmost class will then automatically get System.Object as its base class, and any descendants will inherit the class members from System.Object.

System.Object deserves a closer look, because any class inherits its useful class members. Table 17.1 provides an overview of each of System.Object's methods. The method declaration column displays how each of the methods are declared inside System.Object.

Table 17.1. System.Object's Methods
Method declaration Description
public virtual string ToString() 
Returns a string representation of the current object by returning its namespace name and classname. This method is virtual and can be overridden to return any string you might find suitable. Often, ToString() is overridden to return information about the state of an object.
public virtual bool Equals(object obj) 
Returns true if the current object is the same instance as obj; other-wise, returns false. Thus, Equals does not compare the state of the two objects (value-based equality) but tests for reference equality. Often though, Equals is overridden in a derived class to support value-based comparisons.
public Type GetType() 
The Type class returned from the GetType method provides access to the metadata of the current object type. GetType was presented in Chapter 7, "Types Part II: Operators, Enumerators, and Strings."
public virtual int GetHashTable() 
Returns an int representation of the object called a hash, which is used for fast access to the object in special collections of objects called hash tables.
protected object MemberwiseClone() 
Returns a shallow copy of the current object, which means a copy of the current object is returned. Shallow refers to the fact that if this object is referencing other objects, only the references are copied, not the referenced objects.
public static bool Equals (object objA, object objB) 
Performs a value-based comparison between objA and objB.
public static bool ReferenceEquals (object objA, bject objB) 
Returns true if objA is referencing the same object as objB.
protected virtual void Finalize() 
This method is also called a destructor. If you override this method, as discussed in Chapter 13, "Class Anatomy Part II: Object Creation and Garbage Collection," the overriding method is called when the object is garbage collected. Finalize is of little practical use.

You can use the functionality of the instance methods inherited by your classes in Table 17.1 simply by calling them through your objects like any other function member, as demonstrated in Listing 17.7.

Listing 17.7 SystemObjectTest.cs
01: using System; 02: 03:   namespace Animals 04:   { 05:    class Dog 06:     { 07:         private string name; 08: 09:         public Dog() 10:         { 11:             name = "unknown"; 12:         } 13: 14:         public Dog(string initialName) 15:         { 16:             name = initialName; 17:         } 18: 19:         public string Name 20:         { 21:             get 22:             { 23:                 return name; 24:             } 25:         } 26:     } 27: } 28: 29: class ObjectTester 30: { 31:     public static void Main() 32:     { 33:         Type dogType; 34:         Animals.Dog myDog = new Animals.Dog("Fido"); 35:         Animals.Dog yourDog = new Animals.Dog("Pluto"); 36:         Animals.Dog sameDog = myDog; 37: 38:         Console.WriteLine("ToString(): " + myDog.ToString()); 39:         dogType = myDog.GetType(); 40:         Console.WriteLine("Type: " + dogType.ToString()); 41: 42:         if(myDog.Equals(yourDog)) 43:             Console.WriteLine("myDog is referencing the same object as yourDog"); 44:         else 45:             Console.WriteLine("myDog and yourDog are referencing different objects"); 46: 47:         if(myDog.Equals(sameDog)) 48:             Console.WriteLine("myDog is referencing the same object as sameDog"); 49:         else 50:             Console.WriteLine("myDog and sameDog are referencing  different objects"); 51: 52:         if(object.ReferenceEquals(myDog, yourDog)) 53:             Console.WriteLine("myDog and yourDog are referencing the same object"); 54:         else 55:             Console.WriteLine("myDog and yourDog are referencing different objects"); 56:     } 57: } ToString(): Animals.Dog Type: Animals.Dog myDog and yourDog are referencing different objects myDog is referencing the same object as sameDog myDog and yourDog are referening different objects 

According to Table 17.1, the ToString method returns a string of the general form:

 <Namespace_name>.<Class_name> 

The Dog class exists in a namespace called Animals, so we should expect the following output from the call to ToString in line 38:

 Animals.Dog 

which is confirmed by the first line of the sample output.

Note

graphics/common.gif

Often, as demonstrated in Listing 17.8 shown in a moment, ToString() is overridden in the derived class to return a string that represents the object's state.


The Type class returned from myDog.GetType() lets you access valuable (metadata) information about the Dog class. In this simple demonstration, we restrict ourselves to asking for the string representation of the type (line 40), which is identical to the format provided by the ToString() method.

Line 42 evaluates whether myDog and yourDog are referencing the same instance.

Line 36 assigns the reference held by myDog to sameDog, so myDog and sameDog are referencing the same object, which is correctly assessed by Equals in line 47.

C# contains the keyword object, which is an alias for the System.Object classname. Recall that we need to use the classname when we call a static method. Therefore, we can use object in line 52 to call the static ReferenceEquals method and test whether myDog and yourDog are referencing the same object instance. In effect, we are performing the same test in line 42 as in line 52.

As shown in Table 17.1 most of the methods contained in System.Object are virtual and can therefore be overridden. Listing 17.8 shows how the ToString method can be overridden to provide information about the state of an object and how Equals can be overridden to perform a value-based comparison between two objects instead of the default reference-based comparison we saw in Listing 17.7.

Note

graphics/common.gif

Any class that overrides the Equals method, such as Dog in Listing 17.8, should also override the GetHashCode method to produce a unique numerical value that identifies the object in a hash-table collection. I have omitted the GetHashCode override to keep the code brief. As a result you will see a warning when you compile Listing 17.8.


Listing 17.8 ObjectOverrideTest.cs
01: using System; 02: 03: namespace Animals 04: { 05:     class Dog 06:     { 07:         private string name; 08: 09:         public Dog() 10:         { 11:             name = "unknown"; 12:         } 13: 14:         public Dog(string initialName) 15:         { 16:             name = initialName; 17:         } 18: 19:         public string Name 20:         { 21:             get 22:             { 23:                 return name; 24:             } 25:         } 26: 27:         public override string ToString() 28:         { 29:             return "Dog name: " + name; 30:         } 31: 32:         public override bool Equals(object obj) 33:         { 34:             Dog tempDog = (Dog) obj; 35: 36:             if(tempDog.Name == name) 37:             { 38:                 return true; 39:             } 40:             else 41:             { 42:                 return false; 43:             } 44:         } 45:     } 46: } 47: 48: class ObjectTester 49: { 50:     public static void Main() 51:     { 52:         Animals.Dog myDog = new Animals.Dog("Fido"); 53:         Animals.Dog yourDog = new Animals.Dog("Fido"); 54: 55:         Console.WriteLine(myDog); 56: 57:         if(myDog.Equals(yourDog)) 58:             Console.WriteLine("myDog has the same name as yourDog"); 59:         else 60:             Console.WriteLine("myDog and yourDog have different names"); 61:     } 62: } Dog name: Fido myDog has the same name as yourDog 

Lines 27-30 override the ToString method to output the content of the instance variable name.

The Equals method is overridden in lines 32-44 to compare the instance variable name of the current Dog object to a Dog object passed to it as an argument.

Recall that a variable of class TransportVehicle in our inheritance hierarchy of Figure 16.1 of Chapter 16, "Inheritance Part I: Basic Concepts" could be used to reference an object of any of the types in the hierarchy, because TransportVehicle was at the top of the hierarchy. Similarly because System.Object implicitly is at the top of any hierarchy, a variable of type System.Object can be used to reference an object of any type whether this be a Car, Shape, Account, Elevator, Bacterium or other. As a result the formal parameter obj declared in line 32 to be of type object is able to reference any object type that may be passed to it. However, just like the variable of type Shape restricted us to access only class members defined in the Shape class even though it referenced the subclass Rectangle, obj will only let us use the few System.Object members presented in Table 17.1, even if it like in this case stores a Dog object. To access the Name property of the Dog object referenced by obj we need to perform a down-cast as shown in line 34 where the Dog object is assigned to tempDog. Notice that to keep the code brief we are not checking with the is or as operators (presented earlier) whether obj actually holds a Dog object. So if anybody provides a different type of object the down cast will generate an exception. tempDog allows us in line 36 to access the Name property of the Dog object and thereby perform the comparison between the name of the Dog object provided as an argument and the name of this current object.

The WriteLine method in line 55 automatically calls ToString of myDog and prints the string returned on the screen. Even though it was impossible for the implementers of WriteLine to predict the object types passed to WriteLine they knew that they all inherited ToString and could therefore confidently let WriteLine call this method on any object argument without causing any problems.

According to lines 52 and 53 both myDog and yourDog are called Fido, so the Boolean expression in line 57 returns true.

NOTE

graphics/common.gif

Any class like Dog in Listing 17.8 that overrides the Equals method, such as Dog in Listing 17.8, should also override the GetHashCode method to produce a unique numerical value that identifies the object in a hash-table collection.



   


C# Primer Plus
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2000
Pages: 286
Authors: Stephen Prata

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