Interfaces and abstract classes in C#

✓ Interface – An interface does not contain any code or data; it just specifies the methods and properties, and a class that inherits from the interface must provide implementation.

✶ A class can inherit from another class and implement an interface at the same time.
✶ You’re not allowed to define any constructors in an interface.
✶ You’re not allowed to define a destructor in an interface.
✶ You cannot specify an access modifier for any method.
✶ An interface is not allowed to inherit from a structure or a class, although an interface can inherit from another interface.

✓ Explicitly implementing an interface

interface ILandBound
{
    int NumberOfLegs();
}
interface IJourney
{
    int NumberOfLegs();
}

class Horse : ILandBound, IJourney
{
    int ILandBound.NumberOfLegs()
    {
        return 4;
    }
    int IJourney.NumberOfLegs()
    {
        return 3;
    }
}

Horse horse = new Horse();

IJourney journeyHorse = horse;
int legsInJourney = journeyHorse.NumberOfLegs();

ILandBound landBoundHorse = horse;
int legsOnHorse = landBoundHorse.NumberOfLegs();

✓ Abstract classes – To declare that creating instances of a class is not allowed, you can declare that the class is abstract by using the abstract keyword.

✓ Abstract methods – An abstract class can contain abstract methods. An abstract method is similar in principle to a virtual method, except that it does not contain a method body. A derived class must override this method.

abstract class GrazingMammal : Mammal, IGrazable
{
    ...
    void IGrazable.ChewGrass()
    {
         // common code for chewing grass
        Console.WriteLine("Chewing grass");
    }
}
class Horse : GrazingMammal, ILandBound
{
    ...
}
class Sheep : GrazingMammal, ILandBound
{
    ...
}

✓ Sealed classes – With C#, you can use the sealed keyword to prevent a class from being used as a base class if you decide that it should not be.

sealed class Horse : GrazingMammal, ILandBound
{
    ...
}

If any class attempts to use Horse as a base class, a compile-time error will be generated.

✓ Sealed methods – You can also use the sealed keyword to declare that an individual method in an unsealed class is sealed. This means that a derived class cannot override this method.

Advertisements

Inheritance in C#

✓ Inheritance
The derived class inherits from the base class, and the methods in the base class become part of the derived class. In C#, a class is allowed to derive from one base class. It is not allowed to derive from two or more classes. However, unless DerivedClass is declared as sealed, you can create further derived classes that inherit from DerivedClass using the same syntax.

Inheritance applies only to classes, not structures. You cannot define your own inheritance hierarchy with structures, and you cannot define a structure that derives from a class or another structure.

//base class
class Vehicle
{
    public void StartEngine(string noiseToMakeWhenStarting)
    {
        Console.WriteLine("Starting engine: {0}", noiseToMakeWhenStarting);
    }
    public void StopEngine(string noiseToMakeWhenStopping)
    {
        Console.WriteLine("Stopping engine: {0}", noiseToMakeWhenStopping);
    }
    public virtual void Drive()
    {
        Console.WriteLine("Default implementation of the Drive method");
    }
}

//derived class
class Airplane : Vehicle
{
    public void TakeOff()
    {
        Console.WriteLine("Taking off");
    }
    public void Land()
    {
        Console.WriteLine("Landing");
    }
    public override void Drive()
    {
        Console.WriteLine("Flying");
    }
}

//derived class
class Car : Vehicle
{
    public void Accelerate()
    {
        Console.WriteLine("Accelerating");
    }
    public void Brake()
    {
        Console.WriteLine("Braking");
    }
    public override void Drive()
    {
        Console.WriteLine("Motoring");
    }
}

// Using the inherited class
Console.WriteLine("Journey by airplane:");
Airplane myPlane = new Airplane();
myPlane.StartEngine("Contact");
myPlane.TakeOff();
myPlane.Drive();
myPlane.Land();
myPlane.StopEngine("Whirr");

Console.WriteLine("\nJourney by car:");
Car myCar = new Car();
myCar.StartEngine("Brm brm");
myCar.Accelerate();
myCar.Drive();
myCar.Brake();
myCar.StopEngine("Phut phut");

✓ Public vs private vs protected access
Public fields and methods of a class are accessible to everyone, whereas private fields and methods of a class are accessible to only the class itself.

You can access a protected base class member not only in a derived class but also in classes derived from the derived class. A protected base class member retains its protected accessibility in a derived class and is accessible to further derived classes.

Arrays in C#

✓ Arrays
An array is an unordered sequence of items, and all the items in an array have the same type. The items in an array live in a contiguous block of memory and are accessed by using an index.

You are not restricted to primitive types as array elements. You can also create arrays of structures, enumerations, and classes. Arrays are reference types and when you declare an array variable, you do not declare its size and no memory is allocated. The array is given memory only when the instance is created.

When you create an array instance, all the elements of the array are initialized to a default value depending on their type(Numeric =0, object = null).

pins = new int[4]; // create an arry with deafault values

int[] pins = new int[4]{ 9, 3, 7, 2 };
int[] pins = { 9, 3, 7, 2 };

Time[] schedule = { new Time(12,30), new Time(5,30) }; // create an array of structures or objects

var names = new[]{"John", "Diana", "James", "Francesca"}; //creating an implicitly typed array

✓ Interating through arrays

int[] pins = { 9, 3, 7, 2 };
for (int index = 0; index < pins.Length; index++)
{
    int pin = pins[index];
    Console.WriteLine(pin);
}

foreach (int pin in pins)
{
    Console.WriteLine(pin);
}

var names = new[] { new { Name = "John", Age = 47 }, new { Name = "Diana", Age = 46 }, new { Name = "James", Age = 20 }, new { Name = "Francesca", Age = 18 } };

foreach (var familyMember in names)
{
    Console.WriteLine("Name: {0}, Age: {1}", familyMember.Name, familyMember.Age);
}

✓ Passing array as parameters

// passing array as parameter
public void ProcessData(int[] data)
{
    foreach (int i in data)
    {
        ...
    }
}

//returning as array
public int[] ReadData()
{
    Console.WriteLine("How many elements?");
    string reply = Console.ReadLine();
    int numElements = int.Parse(reply);
    int[] data = new int[numElements];
    for (int i = 0; i < numElements; i++)
    {
        Console.WriteLine("Enter data for element {0}", i);
        reply = Console.ReadLine();
        int elementData = int.Parse(reply);
        data[i] = elementData;
    }
    return data;
}

✓ Multidimensional arrays

int[,] items = new int[4, 6]; //two dimensional array
int[, ,] cube = new int[5, 5, 5]; // three dimensional array

✓ Jagged arrays – In jagged array, each column has a different length

int[][] items = new int[4][];
int[] columnForRow0 = new int[3];
int[] columnForRow1 = new int[10];
int[] columnForRow2 = new int[40];
int[] columnForRow3 = new int[25];
items[0] = columnForRow0;
items[1] = columnForRow1;
items[2] = columnForRow2;
items[3] = columnForRow3;

✓ A params Array

// method to determine the minimum value in a set of values passed as parametersclass Util
{
    public static int Min(int[] paramList)
    {
        if (paramList == null || paramList.Length == 0)
        {
            throw new ArgumentException("Util.Min: not enough arguments");
        }
        int currentMin = paramList[0];
        foreach (int i in paramList)
        {
             if (i < currentMin)
             {
                 currentMin = i;
             }
         }
        return currentMin;
    }
}

// Using min method
int[] array = new int[3];
array[0] = first;
array[1] = second;
array[2] = third;
int min = Util.Min(array);

int min = Util.Min(new int[] {first, second, third});

✓ Declaring a params Array

class Util
{
    public static int Min(params int[] paramList)
    {
        // code exactly as before
    }
}

// Using min method
int min = Util.Min(first, second, third);

Enumerations and structures in C#

✓ Enumerations – Enumerations are value type.

// declaring an enumeration
enum Season { Spring, Summer, Fall, Winter }

//using enumeration
Season colorful = Season.Fall;
Console.WriteLine(colorful); // writes out 'Fall'

string name = colorful.ToString();
Console.WriteLine(name); // also writes out 'Fall'

Console.WriteLine((int)colorful); // Casting. Writes out '2'

//A specific integer constant can also associate with an enumeration literal
enum Season { Spring = 1, Summer, Fall, Winter }

// Enum can also created with different data type
enum Season : short { Spring, Summer, Fall, Winter }

enum Month
{
    January, February, March, April, May, June, July, August, September,
    October, November, December
}
Month first = Month.January;
Console.WriteLine(first); // January
first++;
Console.WriteLine(first); // February

✓ Structures – A structure is a value type, and its instances are live on the stack. On the otherhand class instances are called objects and live on the heap.

In C#, the primitive numeric types int, long, and float are aliases for the structures System.Int32, System.Int64, and System.Single.

Operators, such as the equality operator (==) and the in-equality operator (!=) can’t be used with structure type variables. However, you can use the built-in Equals() method exposed by all structures to compare them.

struct Time
{
private int hours, minutes, seconds;
public Time(int hh, int mm)
{
hours = hh;
minutes = mm;
seconds = 0;
}
}

Time now = new Time(12, 30);
Time copy = now;

When you copy a structure variable, each field on the left side is set directly from the corresponding field on the right side.


struct Time
{
    private int hours, minutes, seconds;
    public Time(int hh, int mm)
    {
        hours = hh;
        minutes = mm;
        seconds = 0;
    }
}

Time now = new Time(12, 30);
Time copy = now;

Familiarizing with value and reference types in C#

✓ Value types – Most of the primitive types, such as int, float, double, and char are collectively called value types. These types have a fixed size, and when you declare a variable, the compiler generates code that allocates a block of memory big enough to hold a corresponding value.

int i = 42;
int copyi = i;
i++; // i now contains 43, but copyi still contains 42

In abvoe example, even though copyi and i happen to hold the same value, there are two blocks of memory containing the value 42: one block for i and the other block for copyi. If you modify the value of i, the value of copyi does not change.

✓ Reference types – A class is a reference type. It is allot a small piece of memory that can potentially hold the address of (or a reference to) variable. The memory for the actual object is allocated only when the new keyword is used to create the object.

Circle c = new Circle(42);
Circle refc = c;

When you declare c as a Circle, c can refer to a Circle object; the actual value held by c is the address of a Circle object in memory. If you declare an additional variable named refc and you assign c to refc, refc will have a copy of the same address as c; in other words, there is only one Circle object, and both refc and c now refer to it.

✓ Using ref and out parameters
When you pass an argument to a method, the corresponding parameter is initialized with a copy of the argument. This is true regardless of whether the parameter is a value type (such as an int), a nullable type (such as int?), or a reference type (such as a WrappedInt).

In this example, the doIncrement method increments a copy of the argument (arg) and not the original argument, as demonstrated here:

static void doIncrement(int param)
{
    param++;
}
static void Main()
{
    int arg = 42;
    doIncrement(arg);
    Console.WriteLine(arg); // writes 42, not 43
}

✓ Creating ref parameters – When using a ref parameter, anything you do to the parameter you also do to the original argument because the parameter and the argument both reference the same data

static void doIncrement(ref int param) // using ref
{
    param++;
}
static void Main()
{
    int arg = 42;
    doIncrement(ref arg); // using ref
    Console.WriteLine(arg); // writes 43
}

Above example, the doIncrement method receives a reference to the original argument rather than a copy, so any changes the method makes by using this reference actually change the original value. That’s why the value 43 is displayed on the console.

✓ Creating out parameters – The compiler checks whether a ref parameter has been assigned a value before calling the method. However, there might be times when you want the method itself to initialize the parameter. You can do this with the out keyword.

static void doInitialize(out int param)
{
    param = 42;
}
static void Main()
{
    int arg; // not initialized
    doInitialize(out arg); // legal
    Console.WriteLine(arg); // writes 42
}

✓ Computer memory – C# divide the memory used for holding data in two separate areas, each of which is managed in a distinct manner. These two areas of memory are traditionally called the stack and the heap.

All value types are created on the stack. All reference types (objects) are cre-ated on the heap (although the reference itself is on the stack). Nullable types are actually reference types, and they are created on the heap.

✓ Stack – Stack memory is organized like a stack of boxes piled on top of one another. When a method is called, each parameter is put in a box that is placed on top of the stack. Each local variable is likewise assigned a box, and these are placed on top of the boxes already on the stack. When a method finishes, you can think of the boxes being removed from the stack.

✓ Heap – Heap memory is like a large pile of boxes strewn around a room rather than stacked neatly on top of each other. Each box has a label indicating whether it is in use. When a new object is created, the runtime searches for an empty box and allocates it to the object. The reference to the object is stored in a local variable on the stack. The runtime keeps track of the number of references to each box. When the last reference disappears, the runtime marks the box as not in use, and at some point in the future it will empty the box and make it available for reuse.

One of the most important reference types in the .NET Framework is the Object class in the System namespace.

Circle c;
c = new Circle(42);
object o;
o = c;

✓ Boxing – We show variables of type object can refer to any item of any reference type. However, variables of type object can also refer to a value type.

int i = 42;
object o = i;

boxing
If you modify the original value of the variable i, the value on the heap referenced through o will not change. Likewise, if you modify the value on the heap, the original value of the variable will not change.

✓ Unboxing – To obtain the value of the boxed copy, you must use what is known as a cast. This is an operation that checks whether it is safe to convert an item of one type to another before it actually makes the copy.

int i = 42;
object o = i; // boxes
i = (int)o; // compiles okay

unboxing

Circle c = new Circle(42);
object o = c; // doesn't box because Circle is a reference variable
int i = (int)o; // compiles okay but throws an exception at run time

✓ is operator – You can use the is operator to verify that the type of an object is what you expect it to be, like this:

WrappedInt wi = new WrappedInt();
object o = wi;
if (o is WrappedInt)
{
    WrappedInt temp = (WrappedInt)o; // This is safe; o is a WrappedInt
}

✓ as operator – The as operator fulfills a similar role to is but in a slightly truncated manner. You use the as operator as follows,

WrappedInt wi = new WrappedInt();
object o = wi;
WrappedInt temp = o as WrappedInt;
if (temp != null)
{
    ... // Cast was successful
}

Creating classes in C#

When you design a class, you systematically arrange information and behavior into a meaningful entity. A program that uses a class should not have to worry how that class actually works internally; the program simply creates an instance of a class and calls the methods of that class.

✓ Encapsulation – Encapsulation is referred to as information hiding. It actually has two purposes: (1) To combine methods and data within a class, (2) To control the accessibility of the methods and data.

✓ Defining a class – The body of a class contains Area method and radius field.

class Circle
{
    int radius;
    double Area()
    {
        return Math.PI * radius * radius;
    }
}

✓ Creating an intance of class

Circle c; // Create a Circle variable
c = new Circle(); // Initialize it

A class is the definition of a type. An object is an instance of that type, and it is created when the program runs. Several objects can be instances of the same class.

✓ Controlling accessibility – We can modify the definition of a field or method with the public and private keywords to control whether it is accessible from the outside.

A class is created with public method and private field as follows,

class Circle
{
    private int radius;
    public double Area()
    {
        return Math.PI * radius * radius;
    }
}

In above class, though radious is not accessible from outside, it will be available within the circle class. Though radius field can be accessed by Area method, there is no way of initializing it. We can use constructor to fix this.

Though variables declared in a method that are not initialized by default, the fields in a class are automatically initialized to 0, false, or null. However, it is still good practice to provide an explicit means of initializing fields.

✓ Constructors – A constructor is a special method that runs automatically when you create an instance of a class. Every class must have a constructor. If you don’t write one, the compiler automatically generates a default constructor for you.

class Circle
{
    private int radius;
    public Circle() // default constructor
    {
        radius = 0;
    }
    public double Area()
    {  
        return Math.PI * radius * radius;
    }
}

Circle c;
c = new Circle();
double areaOfCircle = c.Area();

Having added a public constructor, you can now use the Circle class and exercise its Area method.

✓ Overloading constructors

class Circle
{
    private int radius;
    public Circle() // default constructor
    {
        radius = 0;
    }
    public Circle(int initialRadius) // overloaded constructor
    {
        radius = initialRadius;
    }
    public double Area()
    {
        return Math.PI * radius * radius;
    }
}

Circle c;
c = new Circle(45);

If you write your own constructor for a class, the compiler does not generate a default constructor. Therefore, if you’ve written your own constructor that accepts one or more parameters and you also want a default constructor, you’ll have to write the default constructor yourself.

✓ Partial classes – With C#, you can split the source code for a class into separate files so that you can organize the definition of a large class into smaller, easier to manage pieces.

// the contents of cir1.cs file
partial class Circle 
{ 
    public Circle() // default constructor 
    {
        this.radius = 0; 
    }
    public Circle(int initialRadius) // overloaded constructor 
    {
        this.radius = initialRadius; 
    }
}
// the contents of cir2.cs file
partial class Circle 
{
    private int radius; 
    public double Area() 
    { 
        return Math.PI * this.radius * this.radius; 
    }
}

When you compile a class that has been split into separate files, you must provide all the files to the compiler.

✓ Static methods and data – In C#, all methods must be declared within a class. However, if you declare a method or a field as static, you can call the method or access the field by using the name of the class. No instance is required.

Defining a field as static makes it possible for you to create a single instance of a field that is shared among all objects created from a single class.

In the following example, the static field NumCircles in the Circle class is incremented by the Circle constructor every time a new Circle object is created.

class Circle
{
    private int radius;
    public static int NumCircles = 0;
    public Circle() // default constructor
    {
        radius = 0;
        NumCircles++;
    }
    public Circle(int initialRadius) // overloaded constructor
    {
        radius = initialRadius;
        NumCircles++;
    }
}

✓ Creating a static field by using the const keyword – You can declare that a field is static but that its value can never change.

class Math
{
    public const double PI = 3.14159265358979323846;
}

✓ Static classes – A static class cannot contain any instance data or methods, and it does not make sense to try to create an object from a static class by using the new operator.

public static class Math
{
    public static double Sin(double x) {...}
    public static double Cos(double x) {...}
    public static double Sqrt(double x) {...}
}

Handling errors and exceptions in C#

It is very difficult to ensure that a piece of code always works as expected. Failures can occur for a large number of reasons, many of which are beyond your control as a programmer. Any applications that you write must be capable of detecting failures and handling them in a graceful manner.

✓ Try and catch mechanism
Write your code within a try block. When the code runs, it attempts to execute all the statements in the try block, and if none of the statements generates an exception, they all run, one after the other, to completion. However, if an error condition occurs, execution jumps out of the try block and into another piece of code designed to catch and handle the exception.

try
{
    int leftHandSide = int.Parse(lhsOperand.Text);
    int rightHandSide = int.Parse(rhsOperand.Text);
}
catch (FormatException fEx)
{
    result.Text = fEx.Message;
}

When a FormatException is thrown, the fEx variable is populated with an object containing the details of the exception. Message property contains a text description of the error that caused the exception.

✓ Unhandled Exceptions – If the calling method does not use a try block or there is no matching catch handler, the calling method immediately exits and execution returns to its caller, where the process is repeated. If a matching catch handler is eventually found, the handler runs and execution continues with the first statement that follows the catch handler in the catching method.

✓ Using multiple catch handlers

try
{
    ...
}
catch (FormatException fEx)
{
    result.Text = fEx.Message;
}
    catch (OverflowException oEx)
{
    result.Text = oEx.Message;
}

✓ Throwing exceptions

switch (month)
{
    case 1 :
        return “January”;
    case 2 :
        return “February”;
    ...
    case 12 :
        return “December”;
    default :
        throw new ArgumentOutOfRangeException(“Bad month”);
}

In above example, what should the method return if the integer argument is less than 1 or greater than 12? The method shouldn’t return anything at all and it should throw an exception. This new excemption needs to caought by catch.

✓ Catching unhandled exceptions – All hitherto unhandled exceptions can be caught using below catch handler

catch (Exception ex)
{
    result.Text = ex.Message;
}

✓ Using finally block

TextReader reader = ...;
...
try
{
string line = reader.ReadLine();
while (line != null)
{
...
line = reader.ReadLine();
}
}
finally
{
if (reader != null)
{
reader.Dispose();
}
}

In above example, even if an exception occurs while reading the file, the finally block ensures that the reader.Dispose statement always executes.