Polymorphism in C#

Polymorphism is the ability of an object oriented language (C# in this context) to allow a base class to define a set of members (formally termed the polymorphic interface) that are available to all descendents. A class’s polymorphic interface is constructed using any number of virtual or abstract members.

A virtual member is a member in a base class that defines a default implementation that may be changed (overridden) by a derived class.

In contrast, an abstract method is a member in a base class that does not provide a default implementation, but does provide a signature. When a class derives from a base class defining an abstract method, it must be overridden by a derived type.

In either case (virtual or abstract), when derived types override the members defined by a base class, they are essentially redefining how they respond to the same request.

Method Overriding – Method Overriding is a process in which a derived class can define its own version of a method, which was originally defined by its base class.

Virtual Keyword – The virtual keyword indicates that the base class wants to define a method which may be (but does not have to be) overridden by a derived class. A virtual method provides a default implementation that all derived types automatically inherit. If a child class so chooses, it may override the method but does not have to.

Note: Subclasses are never required to override virtual methods.

Override Keyword – The override keyword is used by a derived class to to change the implementation details of a virtual method (defined in the base class). Each overridden method is free to leverage the default behavior of the parent class using the base keyword.

Sealed Keyword – The sealed keyword is basically applied to classes to prevent other types from extending its behavior via inheritance.

It can also be applied to virtual methods to prevent derived types from overriding those methods. Ex.

public override sealed void GiveBonus(float amount)
{
...
}

Any effort to override the above sealed method in the derived class will generate compile time error.

Abstract Classes – The abstract keyword can be used in the class definition to prevent direct creation of an instance of the class. Although abstract classes cannot be created directly, it is still assembled in memory when derived classes are created. Thus, it is perfectly fine for abstract classes to define any number of constructors that are called indirectly when derived classes are allocated.

An abstract class can define any number of abstract members (members that does not supply a default implementation, but must be accounted for by each derived class).

The polymorphic interface of an abstract base class simply refers to its set of virtual and abstract methods. Methods marked with abstract are pure protocol. They simply define the name, return type (if any), and parameter set (if required).

If you do not override an abstract method (of the base abstract class) in the derived class, the derived class will also be considered abstract, and would have to be marked abstract with the abstract keyword.

Although it is not possible to directly create an instance of an abstract base class, you can freely store references to any subclass with an abstract base variable.

Q: What is an efficient way to force each child class to override a virtual method?

A: To force each child class to override a virtual method, we can better define an abstract method (which by definition means you provide no default implementation whatsoever), in an abstract class.

Inheritance in C#

Inheritance is the ability of an object oriented language (C# in this context) to build new class definitions based on existing class definitions. Inheritance allows us to extend the behavior of a base (parent) class by inheriting core functionality into the derived subclass (child class). Inheritance promotes code re-usability.

Inheritance preserves encapsulation – private members of the base class can never be accessed from an object reference of the derived class. Private members can only be accessed by the class that defines it.

C# does not support Multiple Inheritance. A class in C# cannot directly derive from two or more base classes.

What is Black Box programming?

A well-encapsulated class should protect its data and hide the details of how it operates from the outside world. This is often termed Black Box programming.

The beauty of this approach is that an object is free to change how a given method is implemented under the hood. It does this without breaking any existing code making use of it, provided that the parameters and return values of the method remain constant.

The notion of Black Box programming is very closely related to the concept of Encapsulation.

Encapsulation in C#

Encapsulation is the ability of an object oriented language (C# in this context) to hide unnecessary implementation details from the object user. Encapsulation makes coding simpler and helps to preserve data integrity.

According to the concept of encapsulation, an object’s internal data should not be directly accessible from an object instance. Members of a class that represent an object’s state should not be marked as public. The state of an object should only be altered indirectly by using public members. C# prefers properties to encapsulate data. Ex.

class ABC
{
// private data members
private int roll;
private int class;
private string name;

// public properties
public int Roll
{
get { return roll; }
set { roll = value; }
}
public int Class
{
get { return class; }
set { class = value; }
}
public string Name
{
get { return name; }
set { name = value; }
}

// constructor
public ABC()
{
// values are assigned to data members via properties
Roll = 10;
Class = 9;
Name = “Rajveer Raj Banti”;
}
}

Evolution of C# (1.0 – 5.0)

C# is a multi-paradigm (structured, imperative, object-oriented, event-driven, functional, generic, reflective, concurrent) programming language. It was developed within Microsoft. The development team which consisted of Scott Wiltamuth, Peter Golde and others was led by Anders Hejlsberg.

The first version of C# was released by Microsoft in July 2000. The latest version of C# is 5.0, which was released on August 15, 2012.

C# 1.0

C# 1.0 was released by Microsoft with Visual Studio 2002. C# 1.0 targets .NET Framework 1.0. It was the first language adopted by developers to build .NET applications.

C# 1.2

C# 1.2 was released by Microsoft with Visual Studio 2003. C# 1.2 targets .NET Framework 1.1.

C# 2.0

C# 2.0 was released by Microsoft with Visual Studio 2005. C# 2.0 targets .NET Framework 2.0.
The new features added in C# 2.0 are as given below:
  • Generics
  • Partial types
  • Anonymous methods
  • Iterators
  • Nullable types
  • Private setters (properties)
  • Method group conversions (delegates)
  • Covariance and Contravariance
C# 3.0

C# 3.0 was released by Microsoft with Visual Studio 2008. It is also compatible with Visual Studio 2010. C# 3.0 targets the .NET Framework 2.0 (Except LINQ/Query Extensions), .NET Framework 3.0 (Except LINQ/Query Extensions) and .NET Framework 3.5.
The new features added in C# 3.0 are as given below:
  • Implicitly typed local variables (var)
  • Object and collection initializers
  • Auto-Implemented properties
  • Anonymous types
  • Extension methods
  • Query expressions
  • Lambda expressions
  • Expression trees
  • Partial Methods
  • LINQ
C# 4.0

C# 4.0 was released by Microsoft with Visual Studio 2010. C# 4.0 targets .NET Framework 4.0.
The new features added in C# 4.0 are as given below:
  • Dynamic binding (Late binding)
  • Named and optional arguments
  • Generic Covariance and Contravariance
  • Embedded interop types ("NoPIA")
C# 5.0

C# 5.0 was released by Microsoft with Visual Studio 2012. C# 5.0 targets .NET Framework 4.5.
The new features added in C# 4.0 are as given below:
  • Asynchronous methods
  • Caller info attributes
Future

The upcoming versions of C# might include the following features:
  • Compiler-as-a-service ("Roslyn")
The Evolution of C# programming language

Casting and Reference Conversions – Differentiate between Upcasting and Downcasting

An object reference can be:
  • Implicitly upcast to a base class reference
  • Explicitly downcast to a subclass reference
Upcasting and downcasting between compatible reference types performs reference conversions: a new reference is (logically) created that points to the same object. 
An upcast always succeeds; a downcast succeeds only if the object is suitably typed.

Upcasting

An upcast operation creates a base class reference from a subclass reference. For example:

Vechicle oVechicle = new Vechicle();
Car oCar = oVechicle; // Upcast

After the upcast, variable oCar still references the same Vechicle object as variable oVechicle. The object being referenced is not itself altered or converted:

Console.WriteLine (oCar == oVechicle); // True

Although oCar and oVechicle refer to the identical object, oCar has a more restrictive view on that object:

Console.WriteLine (oCar.Name); // OK
Console.WriteLine (oCar.VechicleCount); // Error: VechicleCount undefined

The last line generates a compile-time error because the variable oCar is of type Car, even though it refers to an object of type Vechicle. To get to its VechicleCount field, you must downcast the Vechicle to a Car.

Downcasting

A downcast operation creates a subclass reference from a base class reference. For example:

Vechicle oVechicle = new Vechicle();
Car oCar = oVechicle; // Upcast

Vechicle oVechicle1 = (Vechicle)oCar; // Downcast
Console.WriteLine (oVechicle1.VechicleCount); // <No error>
Console.WriteLine (oVechicle1 == oCar); // True
Console.WriteLine (oVechicle1 == oVechicle); // True

As with an upcast, only references are affected—not the underlying object. A downcast requires an explicit cast because it can potentially fail at runtime:

Maruti oMaruti = new Maruti();
Car oCar = oMaruti; // Upcast always succeeds
Vechicle oVechicle = (Vechicle)oCar; // Downcast fails: oCar is not a Car

If a downcast fails, an InvalidCastException is thrown. This is an example of runtime type checking.