C# Basics

Class

Properties set and get and Encapsulation

class Person
{
  private string name; // field

  public string Name   // property
  {
    get { return name; }   // get method
    set { name = value; }  // set method : set(string value)
  }
}

Inheritance

The following illustration shows a class WorkItem that represents an item of work in some business process. Like all classes, it derives from System.Object and inherits all its methods. WorkItem adds six members of its own. These members include a constructor, because constructors aren’t inherited. Class ChangeRequest inherits from WorkItem and represents a particular kind of work item. ChangeRequest adds two more members to the members that it inherits from WorkItem and from Object. It must add its own constructor, and it also adds originalItemID. Property originalItemID enables the ChangeRequest instance to be associated with the original WorkItem to which the change request applies.

Inheritance

Polymorphism

Base classes may define and implement virtual methods, and derived classes can override them, which means they provide their own definition and implementation. At run-time, when client code calls the method, the CLR looks up the run-time type of the object, and invokes that override of the virtual method. In your source code you can call a method on a base class, and cause a derived class’s version of the method to be executed.

Example:

public class A
{
    public virtual void DoWork() { }
}
public class B : A
{
    public override void DoWork() { }
}

A derived class can stop virtual inheritance by declaring an override as sealed. Stopping inheritance requires putting the sealed keyword before the override keyword in the class member declaration.

public class C : B
{
    public sealed override void DoWork() { }
}

In the previous example, the method DoWork is no longer virtual to any class derived from C. It’s still virtual for instances of C, even if they’re cast to type B or type A. Sealed methods can be replaced by derived classes by using the new keyword:

public class D : C
{
    public new void DoWork() { }
}

A derived class that has replaced or overridden a method or property can still access the method or property on the base class using the base keyword:

public class Base
{
    public virtual void DoWork() {/*...*/ }
}
public class Derived : Base
{
    public override void DoWork()
    {
        //Perform Derived's work here
        //...
        // Call DoWork on base class
        base.DoWork();
    }
}

Abstract Class

The abstract modifier indicates that the thing being modified has a missing or incomplete implementation. The abstract modifier can be used with classes, methods, properties, indexers, and events. Use the abstract modifier in a class declaration to indicate that a class is intended only to be a base class of other classes, not instantiated on its own. Members marked as abstract must be implemented by non-abstract classes that derive from the abstract class.

abstract class Shape
{
    public abstract int GetArea(); // implicitly a virtual method
}

class Square : Shape
{
    private int _side;

    public Square(int n) => _side = n;

    // GetArea method is required to avoid a compile-time error.
    public override int GetArea() => _side * _side;

    static void Main()
    {
        var sq = new Square(12);
        Console.WriteLine($"Area of the square = {sq.GetArea()}");
    }
}
// Output: Area of the square = 144

Interface

An interface defines a contract. Any class or struct that implements that contract must provide an implementation of the members defined in the interface. An interface may define a default implementation for members. It may also define static members in order to provide a single implementation for common functionality.

Example:

interface IPoint
{
    // Property signatures:
    int X { get; set; }
    int Y { get; set; }
    double Distance { get; }
}

class Point : IPoint
{
    // Constructor:
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    // Property implementation:
    public int X { get; set; }
    public int Y { get; set; }

    // Property implementation
    public double Distance =>
       Math.Sqrt(X * X + Y * Y);
}

class MainClass
{
    static void PrintPoint(IPoint p)
    {
        Console.WriteLine("x={0}, y={1}", p.X, p.Y);
    }

    static void Main()
    {
        IPoint p = new Point(2, 3);
        Console.Write("My Point: ");
        PrintPoint(p);
    }
}
// Output: My Point: x=2, y=3

A class can inherit only one abstract class, but many interfaces.

Operator Overloading

Example:

public readonly struct Fraction
{
    private readonly int num;
    private readonly int den;

    public Fraction(int numerator, int denominator)
    {
        if (denominator == 0)
        {
            throw new ArgumentException("Denominator cannot be zero.", nameof(denominator));
        }
        num = numerator;
        den = denominator;
    }

    public static Fraction operator +(Fraction a) => a;
    public static Fraction operator -(Fraction a) => new Fraction(-a.num, a.den);

    public static Fraction operator +(Fraction a, Fraction b)
        => new Fraction(a.num * b.den + b.num * a.den, a.den * b.den);

    public static Fraction operator -(Fraction a, Fraction b)
        => a + (-b);

    public static Fraction operator *(Fraction a, Fraction b)
        => new Fraction(a.num * b.num, a.den * b.den);

    public static Fraction operator /(Fraction a, Fraction b)
    {
        if (b.num == 0)
        {
            throw new DivideByZeroException();
        }
        return new Fraction(a.num * b.den, a.den * b.num);
    }

    public override string ToString() => $"{num} / {den}";
}

public static class OperatorOverloading
{
    public static void Main()
    {
        var a = new Fraction(5, 4);
        var b = new Fraction(1, 2);
        Console.WriteLine(-a);   // output: -5 / 4
        Console.WriteLine(a + b);  // output: 14 / 8
        Console.WriteLine(a - b);  // output: 6 / 8
        Console.WriteLine(a * b);  // output: 5 / 8
        Console.WriteLine(a / b);  // output: 10 / 4
    }
}

Delegate

A delegate is a type that represents references to methods with a particular parameter list and return type. Delegates are used to pass methods as arguments to other methods. Event handlers are nothing more than methods that are invoked through delegates.

A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++.

You can declare delegates using any of the following methods:

// Declare a method with the same signature as the delegate. static void Notify(string name) { Console.WriteLine($”Notification received for: {name}”); }

// Create an instance of the delegate. Del del1 = new Del(Notify);


- Assign a method group to a delegate type:
```c#
Del del2 = Notify;

Event

Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers.

Event

. NET provides the EventHandler and EventHandler<TEventArgs> delegates to support most event scenarios. Use the EventHandler delegate for all events that don’t include event data. Use the EventHandler<TEventArgs> delegate for events that include data about the event. These delegates have no return type value and take two parameters (an object for the source of the event and an object for event data).

This tutorial from Microsoft document offers three very clear examples: How to: Raise and Consume Events.

Others

readonly vs. const

ReadOnly Keyword Const Keyword
In C#, readonly fields can be created using readonly keyword In C#, constant fields are created using const keyword.
ReadOnly is a runtime constant. Const is a compile time constant.
The value of readonly field can be changed. The value of the const field can not be changed.
It cannot be declared inside the method. It can be declared inside the method.
In readonly fields, we can assign values in declaration and in the constructor part. In const fields, we can only assign values in declaration part.
It can be used with static modifiers. It cannot be used with static modifiers.

base

The base keyword is used to access members of the base class from within a derived class. Use it if you want to:

static

Use the static modifier to declare a static member, which belongs to the type itself rather than to a specific object.

var

Variables that are declared at method scope can have an implicit “type” var. A common use of the var keyword is with constructor invocation expressions. The use of var allows you to not repeat a type name in a variable declaration and object instantiation

var xs = new List<int>();

ref

The ref keyword indicates that a variable is a reference, or an alias for another object.

It’s used in five different contexts (eee examples in this article):

Further reading

For the following topics, I haven’t dive into them, but I hope I could in the future. I just post some interesting references for further reading.

Reference