C Sharp Programming/Objects

From Wikibooks, the open-content textbooks collection

Jump to: navigation, search

Contents

[edit] Introduction

The .NET framework consists of several languages, all which follow the "object orientated programming" (OOP) approach to software development. This standard defines that all objects support

  • Inheritance - the ability to inherit and extend existing functionality.
  • Encapsulation - the ability to allow the user to only see specific parts, and to interact with it in specific ways.
  • Polymorphism - the ability for an object to be assigned dynamically, but with some predictability as to what can be done with the object.

Objects are synonymous with objects in the real world. Think of any object and think of how it looks and how it is measured and interacted with. When creating OOP languages, the reasoning was that if it mimics the thought process of humans, it would simplify the coding experience.

For example, let's consider a chair, and its dimensions, weight, colour and what is it made out of. In .NET, these values are called "Properties". These are values which define the object's state. Be careful, as there are two ways to expose values: Variables and Properties. The recommended approach is expose Properties and not variables.

So we have a real-world idea of the concept of an object. In terms of practicality for a computer to pass information about, passing around an object within a program would consume a lot of resources. Think of a car, how many properties that has - 100's, 1000's. A computer passing this information about all the time will waste memory, processing time and therefore a bad idea to use. So objects come in 2 flavours:

  • Reference types
  • Value types

[edit] Reference and Value Types

A reference type is like a pointer to the value. Think of it like a piece of paper with a street address on it, and the address leads to your house - your object with hundreds of properties. If you want to find it, go to where the address says! This is exactly what happens inside the computer. The reference is stored as a number, corresponding to somewhere in memory where the object exists. So instead of moving an object around - like building a replica house every time you want to look at it - you just look at the original.

A value type is the exact value itself. Values are great for storing small amounts of information: numbers, dates etc.

There are differences in the way they are processed, so we will leave that until a little later in the article.

As well as querying values, we need a way to interact with the object so that some operation can be performed. Think of files - its all well and good knowing the length of the file, but how about Read()'ing it? Therefore, we can use something called methods as a way of performing actions on an object.

An example would be a rectangle. The properties of a rectangle are:

  • Length
  • Width

The "functions" (or methods in .NET) would be:

  • Area ( = Length * Width )
  • Perimeter ( = 2 * Length + 2 * Width)

Methods vary from Properties because they require some transformation of data to achieve a result. Methods can either return a result (such as Area) or not. Like above with the chair, if you Sit() on the chair, there is no expected reaction, the chair just ... works!

[edit] System.Object

To support the first rule of OOP - Inheritance, we define something that all objects will derive from - this is System.Object, also known as Object or object. This object defines some methods that all objects can use should they need to. These methods include:

  • GetHashCode() - retrieve a number unique to that object.
  • GetType() - retrieves information about the object like method names, the objects name etc.
  • ToString() - convert the object to a textual representation - usually for outputting to the screen or file.

Since all objects derive from this class (whether you define it or not), any class will have these 3 methods ready to use. Since we always inherit from System.Object, or a class that itself inherits from System.Object, we therefore enhance and/or extend its functionality. Like in the real world that humans, cats, dogs, birds, fish are all an improved and specialised version of an "organism".

[edit] Object basics

All objects by default are reference types. To support value types, objects must instead inherit from the System.ValueType abstract class, rather than System.Object.

[edit] Constructors

When objects are created, they are initialized by the "constructor". The constructor sets up the object, ready for use. Because objects need to be created before being used, the constructor is created implicitly, unless it is defined differently by the developer. There are 3 types of constructor:

  • Static Constructor
  • Default constructor - takes no parameters.
  • Overloaded constructor - takes parameters.

Overloaded constructors automatically remove the implicit default constructor, so a developer must explicitly define the default constructor if they want to use it.

[edit] Static Constructor

A static constructor is first called when the runtime first accesses the class. Static variables are accessible at all times, so the runtime must initialize it on its first access. The example below, when stepping through in a debugger, will show that static MyClass() is only accessed when the MyClass.Number variable is accessed.

using System;
using System.Collections.Generic;
using System.Text;
 
namespace StaticConstructors
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 0;
            int j = 0;
            Console.WriteLine("Static Number = " + MyClass.Number);
        }
    }
 
    class MyClass
    {
        private static int number;
        public static int Number { get { return number; } }
        static MyClass()
        {
            Random r = new Random();
            number = r.Next();
        }
    }
}

[edit] Default Constructor

The default constructor takes no parameters and is implicitly defined if no other constructors exist. The code sample below show the before, and after result of creating a class.

//Created by the developer
class MyClass
{
}
 
//Created by the compiler
class MyClass : System.Object
{
     public MyClass() : base()
     {
     }
}

[edit] Overloaded Constructors

To initialize objects in various forms, the constructors allow customization of the object by passing in parameters.

 class MyClass
    {
        private int number;
        public int Number { get { return number; } }
 
        public MyClass()
        {
            Random r = new Random();
            number = r.Next();
        }
 
        public MyClass(int seed)
        {
            Random r = new Random(seed);
            number = r.Next();
        }
   }

[edit] Calling other constructors

To minimise code, if another constructor implements the functionality better, you can instruct the constructor to call an overloaded (or default) constructor with specific parameters.

 class MyClass
    {
        private int number;
        public int Number { get { return number; } }
 
        public MyClass() : 
             this ( DateTime.Now.Milliseconds ) //Call the other constructor passing in a value.
        {
 
        }
 
        public MyClass(int seed)
        {
            Random r = new Random(seed);
            number = r.Next();
        }
   }

Base classes constructors can also be called instead of constructors in the current instance

 class MyException : Exception
    {
        private int number;
        public int Number { get { return number; } }
 
        public MyException ( int errorNumber, string message, Exception innerException) : base( message, innerException )
        {
             number = errorNumber;
        }
   }

[edit] Destructors

As well as being "constructed", objects can also perform cleanup when they are cleared up by the garbage collector. The garbage collector only runs when either directly invoked, or has reason to reclaim memory, therefore the destructor may not get the chance to clean up resources for a long time. In this case, look into use of the Dispose() method, from the IDisposable interface.

Destructors are recognised via the use of the ~ symbol in front of a constructor with no access modifier e.g.

 class MyException : Exception
    {
        private int number;
        public int Number { get { return number; } }
 
        public MyException ( int errorNumber, string message, Exception innerException) : base( message, innerException )
        {
             number = errorNumber;
        }
 
        ~MyException()
        {
        }
   }