C# – Encapsulation

Encapsulation

Is about creating a boundary around an object to separate its public and private implementation details in the class file.

Example

public class Contact
{
	private string fname;
	private string lname;
	private string emailaddr;
	private string phoneno;
	private string addr;
	private string cname;
	private byte[] photo;
	private DateTime dob;

	public string FirstName
	{
		get { return fname; }
		set { fname = value; }
	}

	public string LastName
	{
		get { return lname; }
		set { lname = value; }
	}

	public string EmailAddress
	{
		get { return emailaddr; }
		set 
		{
			if(emailaddr.Contains("@") && emailaddr.Contains("."))
			{
				emailaddr = value;
			}
			else 
			{
				throw new Exception("Invalid Email address!");
			}
		}
	}

	public string PhoneNo
	{
		get { return phoneno; }
		set { phoneno = value; }
	}

	public string Address
	{
		get { return addr; }
		set { addr = value; }
	}

	public string CompanyName
	{
		get { return cname; }
		set { cname = value; }
	}

	public byte[] Photo
	{
		get { return photo; }
		set { photo = value; }
	}

	public DateTime BirthDate
	{
		get { return dob; }
		set
		{
			if ((DateTime.Today.Year - value.Year) > 18)
			{
				dob = value;
			}
			else
			{
				throw new Exception("Invalid birth date. Age must be greater than 18.");
			}
	    }
    }
}

The Contact class stores contact information in private variables which are hidden from the external access. The access to the private variables can be granted through public properties.

Classes and Objects

Classes and Objects

Classes

Classes and objects are used everywhere in C# and .Net framework.

Class is a blueprint of creating a type which groups data and behavior of a type.

Class contains properties, methods and events.

Object

Is a instance of a class.

public class Employee
{
	...
}

Employee obj = new Employee();

Related Article
Class

C# – Interface

Interface

Interface represents a contract. A set of public methods any implementing class has to have.

  • Provides specification rather than an implementation for its members.
  • Interface members are all implicitly abstract
  • A class or struct can implement multiple interfaces
  • Interface can contain methods, properties, events and indexers
  • Interface members are always implicitly public and cannot declare an access modifier.
  • Implementing interface means providing a public implementation for all its members.
public interface IEnumerator
{
	bool MoveNext();
	object Current { get; }
	void Reset();
}

// Here's a class that implements this interface:

class Countdown : IEnumerator
{
	int count = 11;
	public bool MoveNext () => count-- > 0;
	public object Current   => count;
	public void Reset()     { throw new NotSupportedException(); }
}

static void Main()
{
	IEnumerator e = new Countdown();
	while (e.MoveNext())
		Console.Write (e.Current);      // 109876543210	
}

Extending an Interface

Interface can be extended just like class, it can derive from other interfaces, one or many interfaces.

public interface IUndoable             { void Undo(); }
public interface IRedoable : IUndoable { void Redo(); }

static void Main()
{
	IRedoable r = null;
	IUndoable u = r;
}

Types that implement IRedoable must also implement the memebers of IUndoable.

Explicit Interface Implementation

When implementing multiple interfaces can result in member signature collision. It can be resolved by explicitly implementing an interface member. The only way to call the explicitly implemented member will be to cast to the interface. It be best used to hide members that are highly specialized and distracting to a type’s normal use case.

interface I1 { void Foo(); }
interface I2 { int Foo(); }

public class Widget : I1, I2
{
	public void Foo ()
	{
		Console.WriteLine ("Widget's implementation of I1.Foo");
	}
	
	int I2.Foo()
	{
		Console.WriteLine ("Widget's implementation of I2.Foo");
		return 42;
	}
}

static void Main()
{
	Widget w = new Widget();
	w.Foo();                      // Widget's implementation of I1.Foo
	((I1)w).Foo();                // Widget's implementation of I1.Foo
	((I2)w).Foo();                // Widget's implementation of I2.Foo
}

Implementing Interface Members Virtually

  • All implicit interface member implemented by default are sealed.
  • It must be marked as virtual or abstract in base class to be overridden.
  • Calling the interface member through base class or the interface calls the subclass implementation.
  • Explicitly implemented interface member cannot be marked as virtual or overridden but it can be reimplemented.
public interface IUndoable { void Undo(); }

public class TextBox : IUndoable
{
	public virtual void Undo() => Console.WriteLine ("TextBox.Undo");
}

public class RichTextBox : TextBox
{
	public override void Undo() => Console.WriteLine ("RichTextBox.Undo");
}

static void Main()
{
	// Calling the interface member through either the base class or the interface
	// calls the subclass’s implementation:
	RichTextBox r = new RichTextBox();
	r.Undo();                          // RichTextBox.Undo
	((IUndoable)r).Undo();             // RichTextBox.Undo
	((TextBox)r).Undo();               // RichTextBox.Undo
}

Reimplementing an Interface in a Subclass

  • A subclass can reimplement any interface member already implemented by a base class.
  • Reimplmentation works wheather member is virtual or not in the base class.
  • Reimplementation also works for member implemented implicitly or explicitly.

The example below shows that TextBox class implements IUndoable interface but implements Undo method explicitly since the method in IUndoable interface is not marked as virtual therefore it needs to be implemented explicitly.

The RichTextBox inherits from TextBox and IUndoable but since the method is not declared virtual in TextBox class therefore it needs to reimplement interface IUndoable Undo() method.

public interface IUndoable { void Undo(); }

public class TextBox : IUndoable
{
	void IUndoable.Undo() => Console.WriteLine ("TextBox.Undo");
}

public class RichTextBox : TextBox, IUndoable
{
	public new void Undo() => Console.WriteLine ("RichTextBox.Undo");
}

static void Main()
{
	// Calling the reimplemented member through the interface calls the subclass’s implementation:
	RichTextBox r = new RichTextBox();
	r.Undo();                 // RichTextBox.Undo      Case 1
	((IUndoable)r).Undo();    // RichTextBox.Undo      Case 2
}

Drawbacks of reimplementation

  • The subclass has no way to call the base class method.
  • The base class author may not anticipate that a method be reimplemented and
    may not allow for the potential consequences.

Better Approach

  • Better design the base class so that reimplementation is not required.
  • Mark virtual when implicitly implementing a member.
  • If you don’t want any further reimplementation, mark it as sealed.
  • Use the following pattern when implementing member explicitly.
public interface IUndoable { void Undo(); }

public class TextBox : IUndoable
{
	//Calls method below
	void IUndoable.Undo() => Undo();
	protected virtual void Undo() => Console.WriteLine( "TextBox.Undo" );
}

public class RichTextBox : TextBox
{
	protercted override void Undo() => Console.WriteLine( "RichTextBox.Undo" );
}
static void Main()
{
	IUndoable r = new RichTextBox();
	r.Undo();		// RichTextBox.Undo
}

Interfaces and Boxing

Casting a struct to an interface causes boxing and calling an implicitly implemented member on a struct does not cause boxing.

interface  I { void Foo();          }
struct S : I { public void Foo() {} }

static void Main()
{
	S s = new S();
	s.Foo();         // No boxing.
	
	I i = s;         // Box occurs when casting to interface.
	i.Foo();
}

Class vs Interface

  • Use classes and subclasses for types that naturally share an implementation.
  • Use interfaces for types that have independent implementations.

Git Example

Abstract class vs Interface

Abstract

  • Abstract class can have abstract members and also non abstract members.
  • Members of abstract can have protected parts, static, etc.
  • A class can inherit only one abstract class.
  • Abstract classes can add more functionality without destroying the child classes.

Interface

  • All the members are implicitly abstract and all the members must override to its derived class.
  • Members of the interface are public with no implementation .
  • A class can inherit one or more interfaces.
  • Modifying interface can have problems with derived classes.

Abstract Class

public abstract class CountryTaxCalculator
{
	public abstract decimal CalculateTaxAmount();
}

public class TaxCalculatorForUS : CountryTaxCalculator
{
	public override deciaml CalculateTaxAmount()
	{
		....
	}
}

public class TaxCalculatorForUK : CountryTaxCalculator
{
	public override deciaml CalculateTaxAmount()
	{
		....
	}
}

public class TaxCalculatorForIN : CountryTaxCalculator
{
	public override deciaml CalculateTaxAmount()
	{
		....
	}
}

Interface Example

public interface ICountryTaxCalculator
{
	decimal CalculateTaxAmount();
}

public class TaxCalculatorForUS : ICountryTaxCalculator
{
	public deciaml CalculateTaxAmount()
	{
		....
	}
}

public class TaxCalculatorForUK : ICountryTaxCalculator
{
	public deciaml CalculateTaxAmount()
	{
		....
	}
}

public class TaxCalculatorForIN : ICountryTaxCalculator
{
	public deciaml CalculateTaxAmount()
	{
		....
	}
}

Abstract classes contains code of their own and interfaces provide a set of property and method signatures with no implementation code at all.

C# – Inheritance

Inheritance

It can inherit from another class to extend or customize the original class. It allows you to reuse the functionality from the base class. A class can inherit from single class but it can be inherited by many classes.

Inheritance not only promotes code reuse but also helps to organize code into hierarchical structures.

public class Contact
{ ... }
public class BusinessContact : Contact
{ ... }
public class ProfessionalContact : Contact
{ ... }
public class PersonalContact : Contact
{ ... }
//base class
public class Asset
{
	public string Name;
}
//inherits from base class
public class Stock : Asset
{
	public long SharesOwned;
}

Derived classes (subclass) are classes which inherits the base class.

Base class is also called super class or the class that gets inherit from.

It is possible to cast operators to test or convert a base type to derived type.

Note

Sometimes it is better to introduce new virtual methods on the base class and implement it in the derived type.

It is important not to overuse inheritance and where possible use abstract class.

Hiding Inherited Members

Sometimes you want to hide the member from base class and redefine the same member in subclass. The new modifier allows you to obscure the base class member and use the subclass. You will need to add the keyword new to redefine the member from the base class into subclass.

using System;

namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
           
           B b = new B();
            b.Counter.Dump();
        }       

    }
    
        public class A 
        {
            public int Counter = 1;
        }
    
        public class B : A 
        {
            public new int Counter = 2;
        }
    
}

Constructors and Inheritance

A subclass must declare its own constructor. The base class constructor are accessible to the derived class but never automatically inherited. A subclass needs to define its own constructor thus it can call the base class constructor with the base keyword. Base class constructors always execute first to ensure that base initialization occurs before specialized initialization.

static void Main()
{
	new Subclass (123);
}

public class Baseclass
{
	public int X;
	public Baseclass () { }
	public Baseclass (int x) { this.X = x; }
}

public class Subclass : Baseclass
{
	public Subclass (int x) : base (x) { }
}


Implicit calling of the parameterless base-class constructor

If the subclass constructor misses the base keyword then the base class parameterless constructor is applied. If there is no parameterless constructor than subclasses base keyword is important.

static void Main()
{
	new Subclass();
}

public class BaseClass
{
	public int X;
	public BaseClass() { X = 1; }
}

public class Subclass : BaseClass
{
	public Subclass() { Console.WriteLine (X); }  // 1
}

Constructor and field initialization order
Once the object is instantiated, the following order of initialization takes place:
1. From subclass to base class: fields initialization and argument base-class constructors evaluation.
2. From base class to subclass: constructor bodies execute.

 public class A 
        {
            //Executes 3rd
            int x = 1;
            public A (int x)
            {
                //Executes 4th
                ....
            }
        }
    
        public class B : A 
        {
            //Executes 1st
            int y = 1;
            //Executes 2nd
            public B (int x): base (x + 1)
            {
                //Executes 5th
                .....
            }
        }

Overloading and Resolution

When overloading is called the most specific type has precedence. The overload is determined during compile time rather than at run time.

// When calling an overload method, the method with the most specific 
// parameter type match has precedence, based on the *compile-time* variable type:

static void Main()
{
	Foo (new House());		// Calls Foo (House)
	
	Asset a = new House();
	Foo (a);				// Calls Foo (Asset)
}

static void Foo (Asset a) { "Foo Asset".Dump(); }
static void Foo (House h) { "Foo House".Dump(); }

public class Asset
{
	public string Name;
}

public class Stock : Asset   // inherits from Asset
{
	public long SharesOwned;
}

public class House : Asset   // inherits from Asset
{
	public decimal Mortgage;
}

Related Article

Polymorphism
Casting and Reference Conversions
Virtual
Abstract
Virtual vs Override
New vs Override
Sealed
Base Keyword