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# – Structs

Structs

Struct is like a class but is a value type and it does not support inheritance. Useful when value-type semantics are desirable. You do not need to define a parameterless constructor but if you do define than you must explictly assign every field.

Struct cannot have:

  • Parameterless constructor
  • Field initializers
  • A finalizer
  • Virtual or protected members
public struct Point
{
	public int X, Y;
	public Point (int x, int y) { X = x; Y = y; }
	// The parameterless constructor is implicit.
}

static void Main()
{
	Point p1 = new Point ();       // p1.x and p1.y will be 0
	p1.Dump();
	
	Point p2 = new Point (1, 1);   // p1.x and p1.y will be 1
	p2.Dump();
}

public struct Point
{
	int x = 1;	// Illegal: cannot initialize field
	int y;
	public Point() { }	// Illegal: cannot have parameterless constructor	
	public Point (int x) { this.x = x; }	// Illegal: must assign field y
}

static void Main() { }

C# – The Object Type

The Object Type

System.Object is the base class for all types. Any type can be upcast to object. Object is a reference type, however you can cast between value type and object with the process of boxing and unboxing.

Boxing and Unboxing

Boxing

Converting value-type instance to a reference-type instance (object class or interface). Copies the value-type instance into the new object.

Unboxing

Requires an explicit cast. Throws InvalidCastException if the stated value type doesn’t match the actual type. Copies the contents of the object into a value-type instance.

int x = 9;
object obj = x;           // Box the int
int y = (int)obj;         // Unbox the int

//InvalidCastException
object obj = 9;
long x = (int) obj;

Static and Runtime Type Checking

Static checking

Checking during compile time, it is to verify the correctness of program without running it.

Runtime Checking

Checked by the CLR during runtime such as when you apply the unboxing.

int i = 3;
object boxed = i;
i = 5;
Console.WriteLine (boxed);    // 3

The GetType Method and typeof Operator

System.Type object represent all types in C#. It can be checked using GetType method or typeof operator. It has properties such as name, assembly, base type, etc.

GetType Method is evaluated during runtime whereas typeof Operator statically compiled.

static void Main()
{
	Point p = new Point();
	Console.WriteLine (p.GetType().Name);             // Point
	Console.WriteLine (typeof (Point).Name);          // Point
	Console.WriteLine (p.GetType() == typeof(Point)); // True
	Console.WriteLine (p.X.GetType().Name);           // Int32
	Console.WriteLine (p.Y.GetType().FullName);       // System.Int32
}

public class Point { public int X, Y; }

The ToString Method

ToString() methods returns the default text representation of a type instance, however you can override the ToString() method on custom types.

static void Main()
{
	int x = 1;
	string s = x.ToString();     // s is "1"
	
	Panda p = new Panda { Name = "Petey" };
	Console.WriteLine (p.ToString()); 		// Petey
}

// You can override the ToString method on custom types:

public class Panda
{
	public string Name;
	public override string ToString() { return Name; }
}

C# – Base keyword

The base Keyword

Accessing members of the base class from within a derived class.

Calling a base-class constructor when creating instance of the derived class.

With base keyword we access base class property non-virtually.

With base we call a method on the base class that has been overridden by another method.

base class is permitted only in a constructor, instance method, instance property accessor.

You cannot use base keyword from within static method.

public class Person
{
    protected string ssn = "555-55-5555";
    protected string name = "John L. Doe";

    public virtual void GetInfo()
    {
        Console.WriteLine("Name: {0}", name);
        Console.WriteLine("SSN: {0}", ssn);
    }
}
class Employee : Person
{
    public string id = "ABC567EFG";
    public override void GetInfo()
    {
        // Calling the base class GetInfo method:
        base.GetInfo();
        Console.WriteLine("Employee ID: {0}", id);
    }
}

class TestClass
{
    static void Main()
    {
        Employee E = new Employee();
        E.GetInfo();
    }
}
/*
Output
Name: John L. Doe
SSN: 555-55-5555
Employee ID: ABC567EFG
*/
static void Main()
{
	House mansion = new House { Name="McMansion", Mortgage=250000 };
	Console.WriteLine (mansion.Liability);      // 250000
}

public class Asset
{
	public string Name;
	public virtual decimal Liability => 0;		// Virtual
}

public class House : Asset
{
	public decimal Mortgage;
	public override decimal Liability => base.Liability + Mortgage;  //using base keyword
}

public class Stock : Asset
{
	public long SharesOwned;
	// We won't override Liability here, because the default implementation will do.
}

C# – Sealed

Sealed

Sealed can be applied to class and class methods. Sealed methods cannot be overridden and sealed class cannot be inherited.

static void Main()
{
	House mansion = new House { Name="McMansion", Mortgage=250000 };
	Console.WriteLine (mansion.Liability);      // 250000
}

public class Asset
{
	public string Name;
	public virtual decimal Liability => 0;		// Virtual
}

public class House : Asset
{
	public decimal Mortgage;
	public sealed override decimal Liability => Mortgage;   // Overridden + sealed
}

// You can also seal the class itself, implicitly sealing all the virtual functions:

public sealed class Stock : Asset { /* ... */ }

Sealing Methods

If you want to override a method than the base method must have modifier marked either virtual, abstract, override.

If you want to seal the overridden method in derived class so that it cannot be further overridden in the inherited class then mark it as sealed.

using System;

namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
           
            CheckingAccount credit = new CheckingAccount();
            credit.ShowCredit();
            credit.SavingCredit();         
            
        } 
    }
    
    public class CreditBase
    {
      public void ShowCredit()
      {
          Console.WriteLine("Base show credit");
      }
      //can be overridden 
      public virtual void SavingCredit()
      {
        Console.WriteLine("Base saving credit");
      }
    }
    
    public class SavingAccount:CreditBase
    {
       //preventing further to be overridden
       public override sealed void SavingCredit()
      {
        Console.WriteLine("Saving saving credit");
      }
    }
    
    public class CheckingAccount:SavingAccount
    {
      //error not possible
      public override sealed void SavingCredit()
      {
        Console.WriteLine("Checking saving credit");
      }
    }
}

C# – New vs Override

New vs Override

Override is bottom up approach, if the method is re-implemented in the subclass than the compiler will always use the subclass method. Even if you call the base class method the compiler will first pick the method from derived class.

New will basically select the method from subclass if there is the keyword new in the method. If you invoke the base class than base class method will be called as in the example below.

static void Main()
{
	Overrider over = new Overrider();
	BaseClass b1 = over;
	over.Foo();                         // Overrider.Foo
	b1.Foo();                           // Overrider.Foo
	
	Hider h = new Hider();
	BaseClass b2 = h;
	h.Foo();                           // Hider.Foo
	b2.Foo();                          // BaseClass.Foo
}

public class BaseClass
{
	public virtual void Foo()  { Console.WriteLine ("BaseClass.Foo"); }
}

public class Overrider : BaseClass
{
 	public override void Foo() { Console.WriteLine ("Overrider.Foo"); }
}

public class Hider : BaseClass
{
	public new void Foo()      { Console.WriteLine ("Hider.Foo"); }
}