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 fromSystem.Object
and inherits all its methods.WorkItem
adds six members of its own. These members include a constructor, because constructors aren’t inherited. ClassChangeRequest
inherits fromWorkItem
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 addsoriginalItemID
. PropertyoriginalItemID
enables theChangeRequest
instance to be associated with the original WorkItem to which the change request applies.
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 theabstract
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
orstruct
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 definestatic
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 delegate type and declare a method with a matching signature: ```c# // Declare a delegate. delegate void Del(string str);
// 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;
- Declare an anonymous method:
// Instantiate Del by using an anonymous method. Del del3 = delegate(string name) { Console.WriteLine($"Notification received for: {name}"); };
- Use a lambda expression:
// Instantiate Del by using a lambda expression. Del del4 = name => { Console.WriteLine($"Notification received for: {name}"); };
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.
. NET provides the
EventHandler
andEventHandler<TEventArgs>
delegates to support most event scenarios. Use theEventHandler
delegate for all events that don’t include event data. Use theEventHandler<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:
- Call a method on the base class that has been overridden by another method.
- Specify which base-class constructor should be called when creating instances of the derived class.
static
Use the static
modifier to declare a static member, which belongs to the type itself rather than to a specific object.
- The normal class (non-static class) can contain one or more
static
methods, fields, properties, events and other non-static members. - Static field of a non-static class is shared across all the instances. So, changes done by one instance would reflect in others.
- Static methods do not consume any memory. Static fields are initialized before you access any static field or create any instance of the type.
- Static methods can be called without creating an object. The
static
methods can only call other static methods and access static members. - If the
static
keyword is applied to a class, all the members of the class must bestatic
.
var
Variables that are declared at method scope can have an implicit “type”
var
. A common use of thevar
keyword is with constructor invocation expressions. The use ofvar
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):
- In a method signature and in a method call, to pass an argument to a method by reference.
- In a method signature, to return a value to the caller by reference.
- In a member body, to indicate that a reference return value is stored locally as a reference that the caller intends to modify. Or to indicate that a local variable accesses another value by reference.
- In a struct declaration, to declare a ref struct or a readonly ref struct.
- In a ref struct declaration, to declare that a field is a reference.
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.
- Attribute: Using Attributes in C#
- Reflection: TutorialPoint C# - Reflection
- C# Collections and Data Structure
- Design Pattern: C# Design Patterns