- Namespace declaration
- class
- Class methods
- Class attributes
- Main method
- Statements and Expressions
- Comments
- Keywords : abstract, as, base, bool, etc
- Identifiers : using C# coding standards
- Pascal Case: for class names and method names.
- camel Case: for method arguments and local variables.
The variables in C#, are categorized into the following types:
- Value types : int, decimal, double, bool, etc
- Reference types : object, dynamic, and string.
- Pointer types : type* identifier
- Implicit type conversion : ToBoolean, ToByte, ToChar, ToDateTime, etc
- Explicit type conversion : cast (int), cast (bool), etc
- Encapsulation is implemented by using access specifiers.
- Public: Access to all code in the program
- Private: Access to only members of the same class
- Note: Properties, Methods, (Classes can be private only if are nested) are private by default.
- Protected: Access to members of the same class and its derived classes
- Internal: Access to the current assembly
- Note: Classes are internal by default.
- Protected Internal: Access to types derived from containing class and the current assembly.
- Private Protected: Access to types derived from the containing class, but only within its containing assembly.
- Note: is valid in C# version 7.2 and later.
Used in the called of the methods.
- Value : swap(int x, int y)
- Reference : swap(ref int x, ref int y)
- Out : swap(out int x)
Used in the called of the methods.
- Value : int? num1 = 45;
- Coalescing Operator (??) : int num2 = num3 ?? 45;
Classes and Structures have the following basic differences:
- classes are reference types and structs are value types
- structures do not support inheritance
- structures cannot have a default constructor
- Properties
- Methods
- Constructor:
- same name of the class
- can have parameters
- can be inherited
- can be overloaded using different ways:
- By using different type of arguments
- By using different number of arguments
- By using different order of arguments
class Classes : ClassesBase {
//1st constructor
public Classes(string constructorParam) : base(constructorParam){}
//2nd constructor
public Classes(double num, string constructorParam) : base(constructorParam){}
//3rd constructor
public Classes(string constructorParam, int num) : base(constructorParam){}
}
class ClassesBase {
//1st constructor base class
public ClassesBase(string constructorParam){}
}
- Destructor:
- same name of the class
- can not have parameters
- cannot be inherited or overloaded
- *The object of a class in C# will be destroyed by the garbage collector in any of the following cases
- Case1: At the end of a program execution each and every object that is associated with the program will be destroyed by the garbage collector.
- Case2: The Implicit calling of the garbage collector occurs sometime in the middle of the program execution provided the memory is full so that the garbage collector will identify unused objects of the program and destroys them.
- Case 3: The Explicit calling of the garbage collector can be done in the middle of program execution with the help of “GC.Collect()” statement so that if there are any unused objects associated with the program will be destroyed in the middle of the program execution.
class Classes {
~Classes(string ctorParam){}
}
*Note: in .NET Core Projects is neccesary call the garbage collector of explicit form (case 3).
class Classes {
~Classes(){}
}
class Program
{
static void Main(string[] args)
{
Program program = new Program();
program.DemoClasses();
GC.Collect();
}
public void DemoClasses()
{
string ctorParam = "Constructor";
Classes clasess = new Classes(ctorParam);
clasess.Display();
}
}
It is the mechanism in C# by which one class is allowed to inherit the features(properties and methods) of another class.
- Base Class (also known as super or parent)
- Derived Class (also known as sub, extended or child)
- Inheritance supports the concept of “reusability”, reuse the properties and methods of the existing class.
- C# does not support multiple inheritance (only using interfaces)
- Inheritance Types:
- Single Inheritance: Class B inheritance from Class A
class B : A {
}
class A {
}
- Multilevel Inheritance: Class C inheritance from Class B and this inheritance from Class A
class C : B {
}
class B : A {
}
class A {
}
- Hierarchical Inheritance: Class B inheritance from Class A, Class C inheritance from Class A
class C : A {
}
class B : A {
}
class A {
}
- Multiple Inheritance(Through Interfaces): Class B inheritance from Class A and interface IA
class B : A, IA {
}
interface IA {
}
class A {
}
The polymorphism is often expressed as 'one interface, multiple functions'.
- static: In static polymorphism, the response to a function is determined at the compile time.
The mechanism of linking a function with an object during compile time is called early binding. It is also called static binding.
- Function Overloading:
- You can have multiple definitions for the same function name in the same scope.
- The definition of the function must differ from each other by the types and/or the number of arguments in the argument list.
- You cannot overload function declarations that differ only by return type.
- Function Overloading:
class A {
void print(int i) {
Console.WriteLine("Printing int: {0}", i);
}
void print(int i, float j) {
Console.WriteLine("Printing int: {0}, float {1}", i, j);
}
void print(string m) {
Console.WriteLine("Printing string: {0}", m);
}
}
- Operator overloading:
- You can redefine or overload most of the built-in operators available in C#.
- Thus a programmer can use operators with user-defined types as well.
class DynamicPolymorphism
{
private double length;
private double height;
public double getVolume()
{
return length * height;
}
public void setLength(double l)
{
length = l;
}
public void setHeight(double h)
{
height = h;
}
public override string ToString()
{
return String.Format("length:{0}, height:{1}", length, height);
}
public static DynamicPolymorphism operator+ (DynamicPolymorphism a, DynamicPolymorphism b)
{
DynamicPolymorphism dynamicPolymorphism = new DynamicPolymorphism();
dynamicPolymorphism.length = a.length + b.length;
dynamicPolymorphism.height = a.height + b.height;
return dynamicPolymorphism;
}
}
- dynamic: In dynamic polymorphism, it is decided at run-time.
- abstract classes:
- Can not create an instance of an abstract class
- Can not declare an abstract method outside an abstract class
- When a class is declared sealed, it cannot be inherited, abstract classes cannot be declared sealed.
- abstract classes:
class DynamicPolymorphism1 : AbstractShape
{
private int length;
private int width;
public DynamicPolymorphism1(int l, int w)
{
length = l;
width = w;
}
public override int AbstractArea()
{
return (length * width);
}
}
abstract class AbstractShape
{
public abstract int AbstractArea();
}
- dynamic:
- virtual functions:
- The "virtual" keyword is used to modify a method, property, indexer, or event declared in the base class and allow it to be overridden in the derived class.
- The "override" keyword is used to extend or modify a virtual/abstract method, property, indexer, or event of base class into derived class.
- The "new" keyword is used to hide a method, property, indexer, or event of base class into derived class.
- virtual functions:
class DynamicPolymorphism2
{
public void CallArea(Shape sh)
{
int a;
a = sh.VirtualArea();
Console.WriteLine("VirtualArea: {0}", a);
}
}
class Rectangle : Shape
{
public Rectangle(int a = 0, int b = 0) : base(a, b)
{
}
public new virtual int VirtualArea()
{
Console.WriteLine("Rectangle class VirtualArea :");
return (width * height);
}
}
class Triangle : Shape
{
public Triangle(int a = 0, int b = 0) : base(a, b)
{
}
public override int VirtualArea()
{
Console.WriteLine("Triangle class VirtualArea :");
return (width * height / 2);
}
}
class Shape
{
protected int width, height;
public Shape(int a = 0, int b = 0)
{
width = a;
height = b;
}
public virtual int VirtualArea()
{
Console.WriteLine("Parent class VirtualArea:");
return 0;
}
}
An interface is defined as a syntactical contract that all the classes inheriting the interface should follow. The interface defines the 'what' part of the syntactical contract and the deriving classes define the 'how' part of the syntactical contract.
- Interfaces are declared using the interface keyword. It is similar to class declaration.
- Interface statements are public by default.
class ExampleInterface : IExampleInterface
{
private int height;
private int width;
private int myProjection;
public ExampleInterface(int h, int w, int p)
{
height = h;
width = w;
myProjection = p;
}
public int projection
{
get => myProjection;
set => myProjection = value;
}
public int GetArea()
{
return (height * width + projection);
}
public void ShowArea()
{
Console.WriteLine("GetArea: {0}", GetArea());
}
}
interface IExampleInterface
{
int projection { get; set; }
int GetArea();
void ShowArea();
}
In c#, Property is an extension of class variable and it provides a mechanism to read, write or change the value of class variable without effecting the external way of accessing it in our applications. Accessors: we can change the internal implementation of class variables and expose it without effecting the external way of accessing it based on our requirements.
- Read-Write: A property which contains a both get and set accessors.
- Read-Only: A property which contains only get accessor.
- Write-Only: A property which contains only set accessor.
class Property
{
//C# standar
private int myVar;
public int MyProperty
{
get { return myVar; }
set { myVar = value; }
}
//C# using Expression Body
private int myProjection;
public int projection
{
get => myProjection; // C# version 6.0+
set => myProjection = value; // C# version 7.0+
}
}
A delegate is a reference type variable that holds the reference to a method, This reference can be changed at runtime.
- Delegates allow methods to be passed as parameters.
- Delegates can be used to define callback methods.
- Delegates can be chained together; for example, multiple methods can be called on a single event.
- Methods don't need to match the delegate signature exactly.
- Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code that can call the referenced method, without having to know at compile time which method will be invoked.
- An interesting and useful property of a delegate is that it does not know or care about the class of the object that it references. Any object will do; all that matters is that the method's argument types and return type match the delegate's. This makes delegates perfectly suited for "anonymous" invocation.
- Simple or multicasting (using + or - operator)
class DelegateClass
{
private int num = 10;
public delegate int MyDelegate(int num);
public int SumNum(int n)
{
num += n;
return num;
}
public int MultNum(int n)
{
num *= n;
return num;
}
public int GetNum()
{
return num;
}
public void PrintNumSimpleDelegate()
{
int x = 4;
Console.WriteLine("-----------------Simple Delegate Example-----------------");
MyDelegate myDelegateSum = new MyDelegate(SumNum);
MyDelegate myDelegateMult = new MyDelegate(MultNum);
myDelegateSum(x);
Console.WriteLine("Value of Num: {0}", GetNum());
myDelegateMult(x);
Console.WriteLine("Value of Num: {0}", GetNum());
Console.WriteLine();
}
public void PrintNumMulticastDelegate()
{
int x = 4;
Console.WriteLine("-----------------Multicast Delegate Example-----------------");
MyDelegate myDelegate = new MyDelegate(SumNum);
myDelegate(x);
Console.WriteLine("Value of Num: {0}", GetNum());
//Add Second Delegate
myDelegate += new MyDelegate(MultNum);
myDelegate(x);
Console.WriteLine("Value of Num: {0}", GetNum());
//Remove Second Delegate
myDelegate -= new MyDelegate(MultNum);
myDelegate(x);
Console.WriteLine("Value of Num: {0}", GetNum());
}
}