CHAPTER 10

image

Class

A class is a template used to create objects. They are made up of members, the main two of which are fields and methods. Fields are variables that hold the state of the object, while methods define what the object can do.

class MyRectangle
{
  int x, y;
  int GetArea() { return x * y; }
}

Object creation

To use a class’s members from outside the defining class, an object of the class must first be created. This is done by using the new keyword, which will create a new object in the system’s memory.

class MyClass
{
  static void Main()
  {
    // Create an object of MyRectangle
    MyRectangle r = new MyRectangle();
  }
}

An object is also called an instance. The object will contain its own set of fields, which can hold values that are different to those of other instances of the class.

Accessing object members

In addition to creating the object, the members of the class that are to be accessible need to be declared as public in the class definition.

class MyRectangle
{
  // Make members accessible for instances of the class
  public int x, y;
  public int GetArea() { return x * y; }
}

The dot operator is used after the object’s name to reference its accessible members.

  
static void Main()
{
  MyRectangle r = new MyRectangle();
  r.x = 10;
  r.y = 5;
  int a = r.GetArea(); // 50
}

Constructor

The class can have a constructor. This is a special kind of method used to instantiate (construct) the object. It always has the same name as the class and does not have a return type, because it implicitly returns a new instance of the class. To be accessible from another class it needs to be declared with the public access modifier.

public MyRectangle() { x = 10; y = 5; }

When a new instance of the class is created the constructor method is called, which in the example above sets the fields to the specified initial values.

static void Main()
{
  MyRectangle r = new MyRectangle();
}

The constructor can have a parameter list, just as any other method. As seen below, this can be used to make the fields’ initial values depend on the parameters passed when the object is created.

class MyRectangle
{
  public int x, y;
  
  public MyRectangle(int width, int height)
  {
    x = width; y = height;
  }
  
  static void Main()
  {
    MyRectangle r = new MyRectangle(20, 15);
  }
}

This keyword

Inside the constructor, as well as in other methods belonging to the object, a special keyword called this can be used. This keyword is a reference to the current instance of the class. Suppose, for example, that the constructor’s parameters have the same names as the corresponding fields. The fields could then still be accessed by using the this keyword, even though they are overshadowed by the parameters.

class MyRectangle
{
  int x, y;
  
  public MyRectangle(int x, int y)
  {
    this.x = x; // set field x to parameter x
    this.y = y;
  }
}

Constructor overloading

To support different parameter lists the constructor can be overloaded. In the example below, the fields will be assigned default values if the class is instantiated without any arguments. With one argument both fields will be set to the specified value, and with two arguments each field will be assigned a separate value. Attempting to create an object with the wrong number of arguments, or with incorrect data types, will result in a compile-time error, just as with any other method.

public MyRectangle()
{
  x = 10; y = 5;
}
 
public MyRectangle(int a)
{
  x =  a; y = a;
}
 
public MyRectangle(int a, int b)
{
  x =  a; y = b;
}

Constructor chaining

The this keyword can also be used to call one constructor from another. This is known as constructor chaining and allows for greater code reuse. Note that the keyword appears as a method call before the constructor body and after a colon.

public MyRectangle()             : this(10,5) {}
public MyRectangle(int a)        : this(a,a)  {}
public MyRectangle(int a, int b) { x = a; y = b; }

Initial field values

If there are fields in the class that need to be assigned initial values, such as in the case of the first constructor above, the fields can simply be initialized at the same time as they are declared. This can make the code a bit cleaner. The initial values will be assigned when the object is created before the constructor is called.

class MyRectangle
{
  int x = 10, y = 20;
}

An assignment of this type is called a field initializer. Such an assignment cannot refer to another instance field.

Default constructor

It is possible to create a class even if no constructors are defined. This is because the compiler will automatically add a default parameterless constructor to such a class. The default constructor will instantiate the object and set each field to its default value.

class MyRectangle {}
class MyApp
{
  static void Main()
  {
    // Calls default constructor
    MyRectangle r = new MyRectangle();
  }
}

Object initializers

When creating an object, as of C# 3.0, it is possible to initialize the object’s public fields within the instantiation statement. A code block is then added, containing a comma-separated list of field assignments. The object initializer block will be processed after the constructor has been called.

class MyRectangle
{
  public int x, y;
}
  
class MyClass
{
  static void Main()
  {
    // Object initializer
    MyRectangle r = new MyRectangle() { x = 10, y = 5 };
  }
}

If there are no arguments for the constructor, the parentheses may be removed.

MyRectangle r = new MyRectangle { x = 10, y = 5 };

Partial class

A class definition can be split up into separate source files by using the partial type modifier. These partial classes will be combined into the final type by the compiler. All parts of a partial class must have the partial keyword and share the same access level.

// File1.cs
public partial class MyPartialClass {}
  
// File2.cs
public partial class MyPartialClass {}

Splitting classes across multiple source files is primarily useful when part of a class is generated automatically. For example, this feature is used by Visual Studio’s graphical user interface builder to separate automatically generated code from manually written code. Partial classes can also make it easier for multiple programmers to work on the same class simultaneously.

Garbage collector

The .NET Framework has a garbage collector that periodically releases the memory used by objects when they are no longer accessible. This frees the programmer from the often tedious and error-prone task of manual memory management. An object will be eligible for destruction when there are no more references to it. This occurs, for example, when a local object variable goes out of scope. An object cannot be explicitly deallocated in C#.

Destructor

In addition to constructors, a class can also have a destructor. The destructor is used to release any unmanaged resources allocated by the object. It is called automatically before an object is destroyed, and cannot be called explicitly. The name of the destructor is the same as the class name, but preceded by a tilde (∼). A class may only have one destructor and it does not take any parameters or return any value.

class MyComponent
{
  public System.ComponentModel.Component comp;
 
  public MyComponent()
  {
    comp = new System.ComponentModel.Component();
  }
  
  // Destructor
  ∼MyComponent()
  {
    comp.Dispose();
  }
}

In general, the .NET Framework garbage collector automatically manages the allocation and release of memory for objects. However, when a class uses unmanaged resources – such as files, network connections, and user interface components – a destructor should be used to free up those resources when they are no longer needed.

Null keyword

The null keyword is used to represent a null reference, which is a reference that does not refer to any object. It can only be assigned to variables of reference type, and not to value type variables. The equal to operator (==) can be used to test whether an object is null.

  
String s = null;
if (s == null) s = new String();

Nullable types

A value type can be made to hold the value null in addition to its normal range of values by appending a question mark (?) to its underlying type. This is called a nullable type and allows the simple types, as well as other struct types, to indicate an undefined value. For example, bool? is a nullable type that can hold the values true, false and null.

bool? b = null;

Null-coalescing operator

The null-coalescing operator (??) returns the left-hand operand if it is not null and otherwise returns the right-hand operand. This conditional operator provides an easy syntax for assigning a nullable type to a non-nullable type.

int? i = null;
int j = i ?? 0; // 0

A variable of a nullable type should not be explicitly cast to a non-nullable type. Doing so will cause a run-time error if the variable has null as its value.

int j = (int)i; // run-time error

Default values

The default value of a reference type is null. For the simple data types the default values are as follows: numerical types become 0, a char has the Unicode character for zero (000) and a bool is false. Default values will be assigned automatically by the compiler for fields. However, explicitly specifying the default value for fields is considered good programming since it makes the code easier to understand. For local variables the default values will not be set by the compiler. Instead, the compiler forces the programmer to assign values to any local variables that are used, so as to avoid problems associated with using unassigned variables.

  
class MyApp
{
  int x;   // field is assigned default value 0
  
  int dummy()
  {
    int x; // local variable must be assigned if used
  }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.213.235