The Object Class


C# defines one special class called object that is an implicit base class of all other classes and for all other types (including the value types). In other words, all other types are derived from object. This means that a reference variable of type object can refer to an object of any other type. Also, since arrays are implemented as classes, a variable of type object can also refer to any array. Technically, the C# name object is just another name for System.Object, which is part of the .NET Framework class library.

The object class defines the methods shown in Table 11-1, which means that they are available in every object. A few of these methods warrant some additional explanation. By default, the Equals(object) method determines if the invoking object refers to the same object as the one referred to by the argument. (That is, it determines if the two references are the same.) It returns true if the objects are the same, and false otherwise. You can override this method in classes that you create. Doing so allows you to define what equality means relative to a class. For example, you could define Equals(object) so that it compares the contents of two objects for equality. The Equals(object, object) method invokes Equals(object) to compute its result.

Table 11-1: Methods of the object Class

Method

Purpose

public virtual bool Equals(object ob)

Determines whether the invoking object is the same as the one referred to by ob.

public static bool Equals(object ob1, object ob2)

Determines whether ob1 is the same as ob2.

protected Finalize( )

Performs shutdown actions prior to garbage collection. In C#, Finalize( ) is accessed through a destructor.

public virtual int GetHashCode( )

Returns the hash code associated with the invoking object.

public Type GetType( )

Obtains the type of an object at runtime.

protected object MemberwiseClone( )

Makes a “shallow copy” of the object. (The members are copied, but objects referred to by members are not.)

public static bool ReferenceEquals(object ob1, object ob2)

Determines whether ob1 and ob2 refer to the same object.

public virtual string ToString( )

Returns a string that describes the object.

The GetHashCode( ) method returns a hash code associated with the invoking object. This hash code can be used with any algorithm that employs hashing as a means of accessing stored objects.

As mentioned in Chapter 9, if you overload the = = operator, then you will usually need to override Equals(object) and GetHashCode( ), because most of the time you will want the = = operator and the Equals(object) methods to function the same. When Equals( ) is overridden, you should also override GetHashCode( ), so that the two methods are compatible.

The ToString( ) method returns a string that contains a description of the object on which it is called. Also, this method is automatically called when an object is output using WriteLine( ). Many classes override this method. Doing so allows them to tailor a description specifically for the types of objects that they create. For example:

 // Demonstrate ToString() using System; class MyClass {   static int count = 0;   int id;   public MyClass() {     id = count;     count++;   }   public override string ToString() {     return "MyClass object #" + id;   } } class Test {   public static void Main() {     MyClass ob1 = new MyClass();     MyClass ob2 = new MyClass();     MyClass ob3 = new MyClass();     Console.WriteLine(ob1);     Console.WriteLine(ob2);     Console.WriteLine(ob3);   } }

The output from the program is shown here:

 MyClass object #0 MyClass object #1 MyClass object #2

Boxing and Unboxing

As explained, all C# types, including the value types, are derived from object. Thus, a reference of type object can be used to refer to any other type, including value types. When an object reference refers to a value type, a process known as boxing occurs. Boxing causes the value of a value type to be stored in an object instance. Thus, a value type is “boxed” inside an object. This object can then be used like any other object. In all cases, boxing occurs automatically. You simply assign a value to an object reference. C# handles the rest.

Unboxing is the process of retrieving a value from a boxed object. This action is performed using an explicit cast from the object reference to its corresponding value type. Attempting to unbox an object into a different type will result in a runtime error.

Here is a simple example that illustrates boxing and unboxing:

 // A simple boxing/unboxing example. using System; class BoxingDemo {   public static void Main() {     int x;     object obj;     x = 10;     obj = x; // box x into an object     int y = (int)obj; // unbox obj into an int     Console.WriteLine(y);   } }

This program displays the value 10. Notice that the value in x is boxed simply by assigning it to obj, which is an object reference. The integer value in obj is retrieved by casting obj to int.

Here is another, more interesting example of boxing. In this case, an int is passed as an argument to the sqr( ) method, which uses an object parameter.

 // Boxing also occurs when passing values. using System; class BoxingDemo {   public static void Main() {     int x;     x = 10;     Console.WriteLine("Here is x: " + x);     // x is automatically boxed when passed to sqr()     x = BoxingDemo.sqr(x);     Console.WriteLine("Here is x squared: " + x);   }   static int sqr(object o) {     return (int)o * (int)o;   } }

The output from the program is shown here:

 Here is x: 10 Here is x squared: 100

Here, the value of x is automatically boxed when it is passed to sqr( ).

Boxing and unboxing allows C#’s type system to be fully unified. All types derive from object. A reference to any type can be assigned to an object reference. Boxing/unboxing automatically handles the details for the value types. Furthermore, because all types are derived from object, they all have access to object’s methods. For example, consider the following rather surprising program:

 // Boxing makes it possible to call methods on a value! using System; class MethOnValue {   public static void Main() {     Console.WriteLine(10.ToString());   } }

This program displays 10. The reason is that the ToString( ) method returns a string representation of the object on which it is called. In this case, the string representation of 10 is 10!

Is object a Universal Data Type?

Given that object is a base class for all other types and that boxing of the value types takes place automatically, it is possible to use object as a “universal” data type. For example, consider the following program that creates an array of object and then assigns various other types of data to its elements:

 // Use object to create a generic array. using System; class GenericDemo {   public static void Main() {     object[] ga = new object[10];     // store ints     for(int i=0; i < 3; i++)       ga[i] = i;     // store doubles     for(int i=3; i < 6; i++)       ga[i] = (double) i / 2;     // store two strings, a bool, and a char     ga[6] = "Generic Array";     ga[7] = true;     ga[8] = 'X';     ga[9] = "end";     for(int i = 0; i < ga.Length; i++)       Console.WriteLine("ga[" + i + "]: " + ga[i] + " ");   } }

The output is shown here:

 ga[0]: 0 ga[1]: 1 ga[2]: 2 ga[3]: 1.5 ga[4]: 2 ga[5]: 2.5 ga[6]: Generic Array ga[7]: True ga[8]: X ga[9]: end

As this program illustrates, because an object reference can hold a reference to any other type of data, it is possible to use an object reference to refer to any type of data. Thus, an array of object as used by the program can store any type of data. Expanding on this concept, it is easy to see how you could construct a stack class, for example, that stored object references. This would enable the stack to store any type of data.

Although the universal-type feature of object is powerful and can be used quite effectively in some situations, it is a mistake to think that you should use object as a way around C#’s otherwise strong type checking. In general, when you need to store an int, use an int variable; when you need to store a string, use a string reference; and so on.

More importantly, beginning with C# 2.0, true generic types are now available to the C# programmer. (Generics are described in Chapter 18.) The addition of generics enables you to easily define classes and algorithms that automatically work with different types of data in a type-safe manner. Because of generics, you will normally not need to use object as a universal type when creating new code. Today, it’s best to reserve object’s universal nature for specialized situations.




C# 2.0(c) The Complete Reference
C# 2.0: The Complete Reference (Complete Reference Series)
ISBN: 0072262095
EAN: 2147483647
Year: 2006
Pages: 300

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