Introducing the C# Class Type

A class is a user-defined type that is composed of field data (often called member variables) and members that operate on this data (such as constructors, properties, methods, events, etc.)

A class is defined in C# the class keyword.

class Car
 {
     // The state of the car
     public int currSpeed;
     // Behavior
     public void SpeedUp(int delta) => currSpeed += delta;
 }

Allocating Objects with The new Keyword

Objects must be allocated into memory using the new keyword.

Car car = new Car();

Understanding Constructors

A programmer will want to assign relevant values to the object's field data before use. A constructor is a special method of a class that is called indirectly when creating an object using the new keyword.

However, unlike a "normal" method, constructors never have a return value (not even void) and are always named identically to the class they are constructing.

Understanding the Role of the Default Constructor

Every C# class is provided with a "freebie" default constructor that you can redefine if need be. By definition, a default constructor never takes arguments. After allocating the new object into memory, the default constructor ensures that all field data of the class is set to an appropriate default value.

class Car
 {
     public int currSpeed;
     public Car()
     {
         currSpeed = 10;    
     }
}

Constructors with out Parameters

Constructors (as well as field and property initializers) can use out parameters starting with C# 7.3.

public Car(int cs, out bool isDanger)
 {
     currSpeed = cs;
     if (cs > 100)
     {
         isDanger = true;
     }else
     {
         isDanger = false;
     }
 }

Understanding the Role of the "this" Keyword

C# supplies a this keyword that provides access to the current class instance.

class Motorcycle
 {
     public string name;
     public void SetDriverName(string name)
     {
         name = name;
     }
    static void Main(string[] args)
     {
         Motorcycle m = new Motorcycle();
         m.SetDriverName("John");
         Console.WriteLine(m.name); // Empty
     }
 }

The problem is that the implementation of the SetDriverName() is assigning the incoming parameter back to itself given that the compiler assumes name is referring to the variable currently in the method scope rather than the name field at the class scope. To inform the compiler that you want to set the current object's "name" data field to the incoming name parameter; simply use this to resolve the ambiguity.

public void SetDriverName(string name) => this.name = name;

Note :A common naming convention is to start private (or internal) class-level variable names with an underscore (e.g _driverName)

Chaning Constructor Calls Using this

Another use of the this kewyord is to design a class using a technique termed constructor chaining. This design pattern is helpful when you have a class that defines multiple constructors.

class Motorcycle
 {
     public int driverIntensity;
     public string driverName;
// constructor chaining.
     public Motorcycle(){}
     public Motorcycle(int intensity) : this(intensity,""){}
     public Motorcycle(string name) : this(0,name){}
     public Motorcycle(int intensity,string name)
     {
         driverName = name;
         driverIntensity = intensity;
     }
 }

If you use optional parameters in your class constructors, you can achive the same benefits as constructor chaining with less code.

class Motorcycle
 {
     public int driverIntensity;
     public string driverName;
// constructor chaining.
     public Motorcycle(int intensity=0,string name="")
     {
         driverName = name;
         driverIntensity = intensity;
     }
 }


Understanding the static Keyword

A C# class may define any number of static members, which are declared using the static keyword. When you do so, the member in question must be invoked directly from the class level, rather than from an object reference variable.

Defining Static Field Data

When you define instance-level data, you know every time you create a new object, the object maintains its own independent copy of the data.

In contrast, when you define static data of a class, the memory is shared by all objects of that category.

class SavingsAccount
 {
     // A static point of data
     public static double currInterestRate = 0.04;
     // Instance-level data
     public double currBalance;
     public SavingsAccount(double b)
     {
         currBalance = b;
     }
 }

Defining Static Methods

public static void SetInterestRate(double n) => currInterestRate = n;
public static double GetInterestRate() => currInterestRate;

When designing any C# class, one of your design challenges is to determine which pieces of data should be defined as static members and which should not. While there are no hard-and-fast rules, remember that a static data field is shared by all objects of that type. Therefore, if you are defining a point of data that all objects should share between them, static is the way to go.

Note : It's a compiler error for a static member to reference non-static members in its implementation. On a related note, it is an error to use "this" keyword on a static member because this implies an object.

Defining Static Constructors

A static constructor is used to initialize static data only once. Since static fields are shared by all objects of class, they should not be initialized in an instance constructor. An instance constructor runs every time a new objects is created, which may reset the shared static data.

A static constructor runs only once, before the class is used for the first time, ensuring that the static data is initialized only one.

Wrong:

class SavingsAccount
 {
     public static double currInterestRate;
     public SavingsAccount()
     {
         currInterestRate = 0.04;
     }
     public static void SetRate(double rate) => currInterestRate = rate;
     public static double GetRate() => currInterestRate;
   static void Main(string[] args)
     {
         SavingsAccount a = new SavingsAccount();
         Console.WriteLine(SavingsAccount.GetRate()); // 0.04
         SavingsAccount.SetRate(0.08);
         Console.WriteLine(SavingsAccount.GetRate()); // 0.08
SavingsAccount a2 = new SavingsAccount();
         Console.WriteLine(SavingsAccount.GetRate()); // 0.04
    }
 }

True

class SavingsAccount
 {
     public static double currInterestRate;
     public SavingsAccount()
     {
     }
     static SavingsAccount()
     {
         currInterestRate = 0.04;
     }
         
   static void Main(string[] args)
     {
         SavingsAccount a = new SavingsAccount();
         Console.WriteLine(SavingsAccount.GetRate()); // 0.04
         SavingsAccount.SetRate(0.08);
         Console.WriteLine(SavingsAccount.GetRate()); // 0.08
         SavingsAccount a2 = new SavingsAccount();
         Console.WriteLine(SavingsAccount.GetRate()); // 0.08
     }
   public static void SetRate(double rate) => currInterestRate = rate;
     public static double GetRate() => currInterestRate;
 }

Rules :

  1. A given class may define only a single static constructor. In other words, the static constructor cannot be overloaded.
  2. A static constructor does not take an access modifier and cannot take any parameters.
  3. A static constructor executes exactly one time, regardless of how many objects of the type are created.
  4. The runtime invokes the static constructor when It creates an instance of the class or before accessing the first static member invoked by the caller.
  5. The static constructor executes before any instance level constructors.

Defining Static Classes

It's also possible to apply the static keyword directly on the class level. When a class has been defined as static, it is not creatable using the new keyword, and it can contain only members or data fields marked with the static keyword.

Note : A class ( or structure ) that exposes only static functionality is often termed a utility class.

static class TimeUtilClass
 { 
 public static void PrintTime() => Console.WriteLine(DateTime.Now.ToShortDateString());
 }

Importing Static Members via the C# using Keyword

C# 6 added support for importing static members with the "using" keyword.


using static System.Console;
using static System.DateTime;
 
static class TimeUtilClass
 {
     public static void PrintTime() => WriteLine(Now.ToShortDateString());
 }

With "static imports" the remainder of your code file is able to directly use the static members of the Console and DateTime classes, without the read to prefix the defining class.