System.Object


System.Object is the ubiquitous base type. All managed types inherit from System.Object, either directly or indirectly. System.Object encompasses the baseline behavior accorded to all managed types. Reference types without an explicit base class inherit System.Object implicitly. Reference types that inherit another type explicitly still inherit System.Object, but indirectly. You can inherit System.Object explicitly. However, that is somewhat redundant and, therefore, is not often done. Value types inherit from System.ValueType, which then inherits System.Object. System.ValueType overrides System.Object members to implement the semantics of a value type.

The members of the System.Object class are explained in Table 3-2.

Table 3-2: System.Object Methods

Method Name

Description

Constructor

public Object()

This is the default constructor of the System.Object. It is called whenever an instance of an object is created. The object keyword is an alias for the System.Object type.

Equals

public virtual bool Equals(object obj)

public static bool Equals(object obj1, object obj2)

Equals returns true if the value of two objects is equal. For reference types, this is an object comparison, which compares identity. For value types, this method compares state, which is an equivalency test. Override this method to perform a more appropriate equality comparison of a derived type.

Finalize

protected override void Finalize().

This method is called when an instance is garbage collected. This method cleans up unmanaged resources associated with an instance. In C#, the destructor is called from the Finalize method. Destructors and finalization are discussed in Chapter 14, "Memory Management."

GetHashCode

public virtual int GetHashCode()

This method returns a hash code of an instance. The default hash code is not guaranteed to be unique or have even distribution. You can override this method to return a meaningful hash code for a derived type or provide better distribution.

GetType

public Type GetType()

This method returns a Type reference, which can be used to inspect the structure of an instance. A Type reference is often the first ingredient in Reflection. Reference is discussed in Chapter 10, "Metadata and Reflections."

MemberwiseClone

protected object MemberwiseClone()

This method creates and returns a new instance of the current object. It performs a shallow copy. For this reason, reference members of the original and cloned object point to the same objects. This method is protected and cannot be overridden in the derived type.

ReferenceEquals

public static bool ReferenceEquals(object obj1, obj2)

This method returns true if the identity, not the state, of two objects is the same.

ToString

public virtual string ToString()

This method returns a string representation of the current instance. The default return is the fully qualified name of the type for the current instance. ToString is frequently overridden to return more pertinent information

Object.Equals Method

For reference types, the Object.Equals method compares identity. References are equal when pointing to the same object. References that point to different objects but have the same state are not equal. You can override the Equals method to perform a value comparison. For value types, the Equals method is already overridden to compare values.

In Applied Microsoft .NET Framework Programming (Microsoft Press, 2001), author Jeffrey Richter mentions four tenets of the Equals method: reflexivity, symmetry, transitivity, and consistency.

  • Reflexive An object is always equal to itself. The obj1.Equal (obj1) call should always return true.

  • Symmetric If obj1.Equals(obj2) is true, then obj2.Equals(obj1) must also be true.

  • Transitive If obj1.Equals(obj2) and obj2.Equals(obj3) are both true, then obj3.Equals(obj1) is true.

  • Consistent If obj1.Equals(obj2) is true, then obj1 and obj2 should always be equal. This assumes that the state of neither object has changed.

The Employee class is a base class. The HourlyEmployee, CommissionedEmployee, and SalariedEmployee classes derive from the Employee class and represent specific types of employees. This is the override of the Equals method in the Employee class:

 public static bool operator==(Employee obj1, Employee obj2) {     return obj1.Equals(obj2); } public static bool operator!=(Employee obj1, Employee obj2) {     return !obj1.Equals(obj2); } public override bool Equals(object obj) {    Employee _obj=obj as Employee;    if(obj==null) {        return false;    }    return this.GetHashCode()==_obj.GetHashCode(); } 

The preceding code also includes overloads of the operators == and !=. The default implementation of these operators will not call the overridden Equals method. This can cause inconsistencies, where the comparison operators behave differently from the Equals method. For this reason, both operators have been overloaded.

When overriding the Equals method, you should also override the GetHashCode method. If not, a compiler warning occurs. Objects that are equal should have the same hash code. Therefore, equality can be based on comparing hash codes. In the Equals method, call GetHashCode to retrieve and compare hash codes.

Object.GetHashCode Method

GetHashCode returns a hash code as a 32-bit integer. Override this method when a reference type is used as a key in a collection. As indicated in the previous section, the Equals and GetHashCode methods should be implemented in tandem.

The fields associated with a hash code should be immutable. If the fields are not immutable, when the fields change, the hash code is also modified. This could necessitate updating the key in a collection. If not, the original key is stale. Stale keys in a collection can cause problems. For this reason, hash codes should not be transient, and the related fields should not change.

The following code shows the GetHashCode method for the Employee class. The EmplID field used for the hash is read-only. After the Employee instance is created, EmplID cannot be modified. It is immutable. There are a variety of algorithms for creating efficient and distributed hash codes—some quite complex. For simplicity, this implementation of GetHashCode simply returns the EmplID property:

 public override int GetHashCode() {     return EmplID; } 

Hash codes are recyclable. When a reference is garbage collected, the hash code is returned to the available pool. The hash code is then assignable to a future instance. For this reason, you should remove dead objects from any collections.

Object.GetType Method

The GetType method returns a Type instance, which describes the current object. Type objects are useful in interrogating the composition of an associated object. Members, such as GetMethods and GetFields, return the underlying architecture of a type. This process is called Reflection.

The following code demonstrates Reflection. The public methods of System.Object are enumerated and displayed. As expected, the methods of Table 3-3 are shown. This excludes the Object.MemberwiseClone method, which is not a public method.

Table 3-3: Member Accessibility

Member Access Modifier

Outside World

Derived Class

public

Yes

Yes

private

No

No

protected

No

Yes

internal

Yes (this assembly)

Yes (this assembly)

internal protected

Yes (this assembly)

Yes

 using System; using System.Collections; using System.Reflection; namespace Donis.CSharpBook{     public class Starter{         public static void Main(){             Object obj=new Object();             Type t=obj.GetType();             foreach(MethodInfo m in t.GetMethods()) {                 Console.WriteLine(m.Name);             }         }     } } 

Object.ToString Method

The ToString method returns a string representation of an instance. The default return is the fully qualified name of the type. Value types override ToString to return the value of the instance. The following code displays the default string representation of a value and a reference type:

 int locala=10; Console.WriteLine(locala.ToString());  // 10 Object obj=new Object(); Console.WriteLine(obj.ToString());     // System.Object 

In the Employee class, ToString is overridden to return the name of the employee:

 public override string ToString() {   return FullName; } 

Object.MemberwiseClone Method

MemberwiseClone returns a new instance of an object. A shallow copy is performed. An object is cloned by performing a bitwise copy of each member. If a member is a value type, the values are copied and there is no side effect. For a member that is a reference type, the reference—not the object—is copied. The result is that the reference members of both objects point to the same memory, as shown in Figure 3-5. When this occurs, any changes in the original object will affect the cloned object, and vice versa.

image from book
Figure 3-5: The result of MemberwiseClone

MemberwiseClone is protected and cannot be overridden. The method is typically called from a derived class when implementing the ICloneable interface. The ICloneable interface defines an interface for cloning objects. The only member is the ICloneable.Clone method.

The following code shows the implementation of the ICloneable.Clone method in the Employee class. As expected, the code delegates to the MemberwiseClone method. In the Employee class, emplName is a member and a reference type. In Main, obj2 is a clone of obj1. The hash of both objects is displayed. This confirms the separate identities of each object. Nonetheless, changes to the employee name affect both objects, which is a nasty side effect. Both objects point to the same name in memory.

     public class Starter{         public static void Main(){             Employee obj1=new Employee(5678);             Employee obj2=(Employee) obj1.Clone();             obj1.Last="Marshall";             obj2.First="Donis";              Console.WriteLine("Obj1 HC "+                 obj1.GetHashCode().ToString());             Console.WriteLine(obj1.EmplID+": "+obj1.FullName);             // 5678: Donis Marshall             Console.WriteLine("Obj2 HC "+                 obj2.GetHashCode().ToString());             Console.WriteLine(obj2.EmplID+": "+obj2.FullName);             // 5678: Donis Marshall         }     }     class Employee: ICloneable {         public Employee(int id) {             if((id<1000) || (id>9999)) {                 throw new Exception(                     "Invalid Employee ID");             }             propID=id;         }         public object Clone() {             return MemberwiseClone();         } //  end of partial listing… 

Object.ReferenceEquals Method

The ReferenceEquals method compares identity. If the objects are the same, ReferenceEquals returns true. Otherwise, false is returned. ReferenceEquals is not virtual and cannot be overridden in the derived class. The following code compares an original object and a cloned object. The objects have the same state but different identities. Because the identities are distinct, the ReferenceEquals method returns false.

     Employee obj1=new Employee(5678);     Employee obj2=(Employee) obj1.Clone();     if(Employee.ReferenceEquals(obj1, obj2)) {         Console.WriteLine("objects identical");     }     else {         Console.WriteLine("objects not identical");     } } 




Programming Microsoft Visual C# 2005(c) The Language
Microsoft Visual Basic 2005 BASICS
ISBN: 0619267208
EAN: 2147483647
Year: 2007
Pages: 161

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