Our Roadmaps
Programming Languages

Learn C#

A comprehensive C# course.

Welcome to the comprehensive C# course. C# is a modern, object-oriented programming language developed by Microsoft.

Table of contents

What is C#?

C# (pronounced "C sharp") is a modern, general-purpose, object-oriented programming language developed by Microsoft and standardized by ECMA and ISO.

Key Characteristics

  • Type-safe: Strong type checking at compile time
  • Object-oriented: Supports classes, inheritance, polymorphism
  • Component-oriented: Built-in support for component software
  • Modern: Garbage collection, exception handling, lambda expressions
  • Versatile: Desktop, web, mobile, gaming, cloud applications

Why learn C#?

1. Wide Platform Support

.NET runs on Windows, macOS, and Linux.

2. Rich Ecosystem

Extensive libraries and frameworks for any task.

3. Career Opportunities

High demand in enterprise software development.

4. Game Development

Unity game engine uses C# for game development.

Installation and Setup

.NET SDK

Download from dotnet.microsoft.com:

dotnet --version
dotnet --list-sdks

IDE Options

  • Visual Studio (Windows) - Full-featured IDE
  • Visual Studio Code - Lightweight with C# extension
  • JetBrains Rider - Cross-platform .NET IDE

Creating a Project

dotnet new console -n MyApp
dotnet new webapi -n MyApi
dotnet new classlib -n MyLibrary

Running

dotnet run
dotnet build
dotnet test

Hello World

using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("Hello, World!");
    }
}

Modern C# 9+ top-level statements:

Console.WriteLine("Hello, World!");

Variables and Data Types

Value Types

// Integers
sbyte s = -128;           // 8-bit
byte b = 255;              // 8-bit unsigned
short sh = 32767;          // 16-bit
int i = 2147483647;        // 32-bit
long l = 9223372036854775807L;  // 64-bit

// Floating point
float f = 3.14f;          // 32-bit
double d = 3.14159;        // 64-bit
decimal dec = 3.14m;       // 128-bit (financial)

// Characters
char c = 'A';

// Booleans
bool flag = true;

Reference Types

string name = "John";      // Immutable string
object obj = new object();  // Base type
dynamic dyn = 10;          // No type checking

var and Type Inference

var name = "John";        // Compiler infers string
var age = 30;             // Compiler infers int
var price = 19.99;        // Compiler infers double

Constants

const double Pi = 3.14159;
const int MaxItems = 100;
const string AppName = "MyApp";

Nullable Types

int? nullableInt = null;
string? nullableString = null;

if (nullableInt.HasValue)
{
    Console.WriteLine(nullableInt.Value);
}

// Null coalescing
int value = nullableInt ?? 0;

Default Values

int i = default;          // 0
bool b = default;         // false
string s = default;        // null

Operators

Arithmetic

int a = 10, b = 3;

Console.WriteLine(a + b);   // 13
Console.WriteLine(a - b);   // 7
Console.WriteLine(a * b);   // 30
Console.WriteLine(a / b);   // 3 (integer division)
Console.WriteLine(a % b);    // 1 (modulus)

Comparison

Console.WriteLine(5 == 5);   // True
Console.WriteLine(5 != 3);   // True
Console.WriteLine(5 > 3);    // True
Console.WriteLine(5 >= 5);   // True

Logical

Console.WriteLine(true && false);  // False
Console.WriteLine(true || false);  // True
Console.WriteLine(!true);          // False

Null Operators

string? name = null;

// Null coalescing
string displayName = name ?? "Anonymous";

// Null conditional
int? length = name?.Length;

// Null coalescing assignment
name ??= "Default";

Ternary

int age = 20;
string status = age >= 18 ? "Adult" : "Minor";

Flow Control

If/Else

int score = 85;

if (score >= 90)
{
    Console.WriteLine("A grade");
}
else if (score >= 80)
{
    Console.WriteLine("B grade");
}
else
{
    Console.WriteLine("Need improvement");
}

Switch

string day = "Monday";

switch (day)
{
    case "Monday":
    case "Tuesday":
    case "Wednesday":
    case "Thursday":
    case "Friday":
        Console.WriteLine("Weekday");
        break;
    case "Saturday":
    case "Sunday":
        Console.WriteLine("Weekend");
        break;
    default:
        Console.WriteLine("Invalid day");
        break;
}

// Switch expression (C# 8+)
string result = day switch
{
    "Saturday" or "Sunday" => "Weekend",
    _ => "Weekday"
};

For Loop

for (int i = 0; i < 5; i++)
{
    Console.WriteLine(i);
}

// Foreach
string[] fruits = { "Apple", "Banana", "Cherry" };
foreach (string fruit in fruits)
{
    Console.WriteLine(fruit);
}

While Loop

int count = 0;
while (count < 5)
{
    Console.WriteLine(count);
    count++;
}

// Do-while
int i = 0;
do
{
    Console.WriteLine(i);
    i++;
} while (i < 5);

Jump Statements

for (int i = 0; i < 10; i++)
{
    if (i == 5)
        break;       // Exit loop
    if (i == 2)
        continue;    // Skip iteration
    Console.WriteLine(i);
}

Methods

Basic Method

static string Greet(string name)
{
    return $"Hello, {name}!";
}

Parameters

// Optional parameters
static void Print(string message, string prefix = "INFO")
{
    Console.WriteLine($"[{prefix}] {message}");
}

// Named arguments
Print(message: "Hello", prefix: "DEBUG");

// Out parameters
static bool TryParse(string s, out int result)
{
    result = int.TryParse(s, out int parsed) ? parsed : 0;
    return parsed != 0;
}

// Ref parameters
static void Increment(ref int value)
{
    value++;
}

// Params for variable arguments
static int Sum(params int[] numbers)
{
    return numbers.Sum();
}

Local Functions

static int Calculate()
{
    int Square(int x) => x * x;

    return Square(5) + Square(3);
}

Expression-bodied Members

class Person
{
    public string Name { get; set; }

    public string Greet() => $"Hello, {Name}!";

    public string Greeting => $"Welcome, {Name}";
}

Strings

Creating Strings

string s1 = "Hello";
string s2 = @"C:\Path\To\File";  // Verbatim string
string s3 = $"Hello, {name}!";    // Interpolated
string s4 = """
    Multi-line
    string
    """;

String Methods

string s = "  Hello, World!  ";

s.Trim()                 // "Hello, World!"
s.TrimStart()           // "Hello, World!  "
s.TrimEnd()             // "  Hello, World!"
s.ToUpper()             // "  HELLO, WORLD!  "
s.ToLower()             // "  hello, world!  "
s.Replace("World", "C#")
s.Split(',')            // ["  Hello", " World!  "]
s.Contains("Hello")     // True
s.StartsWith("  Hello") // True
s.EndsWith("!  ")       // True
s.IndexOf("World")      // 9
s.Substring(2, 5)       // "Hello"
s.Insert(5, " there")  // "  Hello there, World!  "
s.Remove(0, 2)         // "Hello, World!  "

String Formatting

string name = "John";
int age = 30;

// String interpolation
$"Name: {name}, Age: {age}";

// Format
string.Format("Name: {0}, Age: {1}", name, age);

// Composite formatting
Console.WriteLine("{0,-10} {1,5}", "Name", "Value");
Console.WriteLine("{0,-10} {1,5}", "Item", 100);

// Date formatting
DateTime now = DateTime.Now;
$"{now:d}"              // 04/08/2026
$"{now:D}"              // Tuesday, April 8, 2026
$"{now:yyyy-MM-dd}"     // 2026-04-08
$"{now:HH:mm:ss}"       // 14:30:00

StringBuilder

using System.Text;

var sb = new StringBuilder();
sb.Append("Hello");
sb.AppendLine(" World");
sb.AppendFormat("Value: {0}", 42);
sb.Insert(5, " there");
sb.Remove(0, 2);
string result = sb.ToString();

Arrays

Creating Arrays

int[] numbers = { 1, 2, 3, 4, 5 };
int[] zeros = new int[5];           // All zeros
string[] names = new string[] { "A", "B" };
var array = new[] { 1, 2, 3 };      // Compiler infers int[]

Multi-dimensional

int[,] matrix = {
    { 1, 2, 3 },
    { 4, 5, 6 }
};

int[,,] cube = new int[2, 3, 4];

// Access
Console.WriteLine(matrix[0, 1]);  // 2

Jagged Arrays

int[][] jagged = new int[3][];
jagged[0] = new[] { 1, 2 };
jagged[1] = new[] { 3, 4, 5 };
jagged[2] = new[] { 6 };

Array Methods

int[] arr = { 5, 2, 8, 1, 9 };

Array.Sort(arr);
Array.Reverse(arr);
Array.Clear(arr);
Array.Resize(ref arr, 10);
int idx = Array.IndexOf(arr, 5);
bool exists = arr.Contains(5);

int min = arr.Min();
int max = arr.Max();
int sum = arr.Sum();

Lists

Creating Lists

var list = new List<int>();
var list2 = new List<int> { 1, 2, 3 };
var names = new List<string> { "John", "Jane" };

List Methods

var list = new List<int> { 1, 2, 3 };

list.Add(4);             // Add element
list.AddRange(new[] { 5, 6 });  // Add multiple
list.Insert(0, 0);       // Insert at index
list.InsertRange(0, new[] { -1, 0 });

list.Remove(3);          // Remove first match
list.RemoveAt(0);         // Remove at index
list.RemoveRange(0, 2);   // Remove range

list.Clear();            // Remove all

bool exists = list.Contains(5);
int idx = list.IndexOf(5);
list.Sort();
list.Reverse();

int count = list.Count;
list.Capacity;

Collections

Dictionary

var dict = new Dictionary<string, int>
{
    { "one", 1 },
    { "two", 2 }
};

dict["three"] = 3;
dict.TryGetValue("one", out int value);
bool exists = dict.ContainsKey("two");

foreach (var kvp in dict)
{
    Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}

foreach (var key in dict.Keys) { }
foreach (var value in dict.Values) { }

HashSet

var set = new HashSet<int> { 1, 2, 3 };

set.Add(4);
set.Add(1);  // No effect (already exists)

bool exists = set.Contains(2);
set.Remove(3);
set.Clear();

set.UnionWith(new[] { 5, 6 });
set.IntersectWith(new[] { 2, 3, 4 });
set.ExceptWith(new[] { 1, 2 });

Queue

var queue = new Queue<int>();

queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);

int first = queue.Peek();   // View without removing
int removed = queue.Dequeue();

Stack

var stack = new Stack<int>();

stack.Push(1);
stack.Push(2);
stack.Push(3);

int top = stack.Peek();     // View without removing
int removed = stack.Pop();

LinkedList

var list = new LinkedList<string>();

list.AddFirst("First");
list.AddLast("Last");
list.AddAfter(list.First, "After First");
list.AddBefore(list.Last, "Before Last");

list.Remove("First");

LINQ

Query Syntax

var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var evens = from n in numbers
            where n % 2 == 0
            select n;

var grouped = from n in numbers
             group n by n % 2 == 0 into g
             select new { IsEven = g.Key, Values = g };

Method Syntax

var numbers = new[] { 1, 2, 3, 4, 5 };

// Filtering
var evens = numbers.Where(n => n % 2 == 0);
var first = numbers.First();
var firstOrNone = numbers.FirstOrDefault(n => n > 10);
var single = numbers.Single(n => n == 3);

// Projection
var doubled = numbers.Select(n => n * 2);
var projected = numbers.Select((n, i) => $"{i}: {n}");

// Ordering
var sorted = numbers.OrderBy(n => n);
var desc = numbers.OrderByDescending(n => n);
var multi = numbers.OrderBy(n => n % 2).ThenBy(n => n);

// Aggregation
int count = numbers.Count();
int sum = numbers.Sum();
int min = numbers.Min();
int max = numbers.Max();
double avg = numbers.Average();
var grouped = numbers.GroupBy(n => n % 2);

// Set operations
int[] a = { 1, 2, 3 };
int[] b = { 3, 4, 5 };
var union = a.Union(b);           // { 1, 2, 3, 4, 5 }
var intersect = a.Intersect(b);    // { 3 }
var except = a.Except(b);          // { 1, 2 }

// Take/Skip
var first3 = numbers.Take(3);
var skip3 = numbers.Skip(3);
var page2 = numbers.Skip(5).Take(5);

// All/Any
bool allPositive = numbers.All(n => n > 0);
bool hasEven = numbers.Any(n => n % 2 == 0);

// Conversion
List<int> list = numbers.ToList();
int[] array = numbers.ToArray();
Dictionary<int, string> dict = numbers.ToDictionary(n => n, n => $"Num {n}");

Deferred Execution

var query = numbers.Where(n => n > 5);  // Not executed yet

numbers.Add(6);  // Modifies source

foreach (var n in query)  // Executes now, includes new element
{
    Console.WriteLine(n);
}

Classes

Basic Class

public class Person
{
    // Fields
    private string _name;

    // Properties
    public string Name
    {
        get => _name;
        set => _name = value ?? throw new ArgumentNullException();
    }

    public int Age { get; set; }

    // Auto-property
    public string Email { get; init; }

    // Constructor
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    // Method
    public string Greet() => $"Hello, I'm {Name}";
}

Access Modifiers

public class PublicClass { }          // Accessible everywhere
internal class InternalClass { }       // Same assembly only

public class MyClass
{
    public string PublicField;         // Everywhere
    private string _privateField;      // This class only
    protected string _protectedField;  // This + derived
    internal string _internalField;    // Same assembly
    protected internal string _tiField; // Internal OR protected
    private protected string _ptField;  // Protected AND internal

    public readonly string Id;        // Set once, anywhere read
    public const double Pi = 3.14159; // Compile-time constant
}

Static Members

public class MathHelper
{
    public static int Add(int a, int b) => a + b;

    public static string AppName { get; } = "MyApp";

    static MathHelper()
    {
        // Static constructor
    }
}

// Usage
var result = MathHelper.Add(1, 2);

Partial Classes

// File1.cs
public partial class User
{
    public string Name { get; set; }
}

// File2.cs
public partial class User
{
    public string Email { get; set; }
}

Inheritance

Basic Inheritance

public class Animal
{
    public string Name { get; set; }

    public virtual void Speak()
    {
        Console.WriteLine("...");
    }
}

public class Dog : Animal
{
    public string Breed { get; set; }

    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

Constructor Inheritance

public class BaseClass
{
    public BaseClass(int value)
    {
        Value = value;
    }

    public int Value { get; }
}

public class DerivedClass : BaseClass
{
    public DerivedClass(int value, string name) : base(value)
    {
        Name = name;
    }

    public string Name { get; }
}

Sealed Classes

public sealed class FinalClass
{
    // Cannot be inherited
}

Abstract Classes

public abstract class Shape
{
    public abstract double Area { get; }

    public string Color { get; set; } = "White";

    public virtual void Display()
    {
        Console.WriteLine($"Color: {Color}");
    }
}

public class Circle : Shape
{
    public double Radius { get; set; }

    public override double Area => Math.PI * Radius * Radius;
}

Interfaces

Basic Interface

public interface IComparable
{
    int CompareTo(object obj);
}

public interface IDrawable
{
    void Draw();
}

public interface IReadable
{
    string Content { get; }
}

Interface Implementation

public class Document : IDrawable, IReadable
{
    public string Content => "Document content...";

    public void Draw()
    {
        Console.WriteLine("Drawing document");
    }
}

// Explicit implementation
public class Reader : IReadable
{
    private string _content = "Data";

    string IReadable.Content => _content;
}

Default Interface Methods (C# 8+)

public interface ILogger
{
    void Log(string message);

    void LogError(string error) => Log($"ERROR: {error}");
}

Records

Basic Record

public record Person(string Name, int Age);

// Usage
var person = new Person("John", 30);
var (name, age) = person;  // Deconstruction

Class-like Record

public record Person
{
    public string Name { get; init; }
    public int Age { get; init; }
}

With Expressions

public record Person(string Name, int Age)
{
    public string Greeting => $"Hello, {Name}!";
}

Immutability

public record Person(string Name, int Age)
{
    public Person WithName(string name) => this with { Name = name };
}

var person = new Person("John", 30);
var updated = person with { Name = "Jane" };  // New instance

Value Equality

var p1 = new Person("John", 30);
var p2 = new Person("John", 30);

Console.WriteLine(p1 == p2);  // True (same values)

Structs

Basic Struct

public struct Point
{
    public double X { get; init; }
    public double Y { get; init; }

    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }

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

readonly Struct

public readonly struct ImmutablePoint
{
    public double X { get; }
    public double Y { get; }

    public ImmutablePoint(double x, double y) => (X, Y) = (x, y);

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

ref Struct

public ref struct Span<int>
{
    private ref int _reference;
    private int _length;

    public Span(ref int reference, int length)
    {
        _reference = ref reference;
        _length = length;
    }
}

Exception Handling

Basic Try/Catch

try
{
    int result = 10 / 0;
}
catch (DivideByZeroException ex)
{
    Console.WriteLine($"Division error: {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}
finally
{
    Console.WriteLine("Always executes");
}

Throwing Exceptions

public void ValidateAge(int age)
{
    if (age < 0)
    {
        throw new ArgumentException("Age cannot be negative", nameof(age));
    }
}

Custom Exceptions

public class ValidationException : Exception
{
    public string Field { get; }

    public ValidationException(string field, string message)
        : base(message)
    {
        Field = field;
    }
}

throw new ValidationException("email", "Invalid email format");

Exception Filters (C# 6+)

try
{
    // Code
}
catch (Exception ex) when (ex is InvalidOperationException or ArgumentNullException)
{
    // Handle specific exceptions
}

File Handling

Reading Files

using System.IO;

// Read all text
string content = File.ReadAllText("file.txt");

// Read all lines
string[] lines = File.ReadAllLines("file.txt");

// Read as stream
using var reader = new StreamReader("file.txt");
while (!reader.EndOfStream)
{
    string line = await reader.ReadLineAsync();
    Console.WriteLine(line);
}

Writing Files

using System.IO;

// Write all text
File.WriteAllText("output.txt", "Hello, World!");

// Write all lines
File.WriteAllLines("output.txt", new[] { "Line 1", "Line 2" });

// Append
File.AppendAllText("output.txt", "\nNew line");

FileInfo

var file = new FileInfo("document.pdf");

if (file.Exists)
{
    long size = file.Length;
    DateTime created = file.CreationTime;
    DateTime modified = file.LastWriteTime;
    file.CopyTo("backup.pdf");
    file.MoveTo("renamed.pdf");
    file.Delete();
}

Directory Operations

Directory.CreateDirectory("newfolder");
Directory.Delete("folder");
Directory.Move("old", "new");

var files = Directory.GetFiles(".", "*.txt");
var dirs = Directory.GetDirectories(".");

Delegates and Events

Delegates

public delegate int Operation(int a, int b);

public static class MathOperations
{
    public static int Add(int a, int b) => a + b;
    public static int Multiply(int a, int b) => a * b;
}

// Usage
Operation op = MathOperations.Add;
Console.WriteLine(op(5, 3));  // 8

op = MathOperations.Multiply;
Console.WriteLine(op(5, 3));  // 15

Generic Delegates

Func<int, int, int> add = (a, b) => a + b;
Action<string> print = Console.WriteLine;
Predicate<int> isEven = n => n % 2 == 0;

Events

public class Button
{
    // Event declaration
    public event EventHandler? Clicked;

    public void OnClick()
    {
        Clicked?.Invoke(this, EventArgs.Empty);
    }
}

// Subscribe
var button = new Button();
button.Clicked += (sender, e) => Console.WriteLine("Clicked!");

// Unsubscribe
button.Clicked -= handler;

Custom EventArgs

public class ValueChangedEventArgs : EventArgs
{
    public int OldValue { get; }
    public int NewValue { get; }

    public ValueChangedEventArgs(int oldValue, int newValue)
    {
        OldValue = oldValue;
        NewValue = newValue;
    }
}

public class Counter
{
    private int _value;

    public event EventHandler<ValueChangedEventArgs>? ValueChanged;

    public int Value
    {
        get => _value;
        set
        {
            var old = _value;
            _value = value;
            ValueChanged?.Invoke(this, new ValueChangedEventArgs(old, value));
        }
    }
}

Async/Await

Basic Async

public async Task<string> FetchDataAsync()
{
    using var client = new HttpClient();
    string result = await client.GetStringAsync("https://api.example.com");
    return result;
}

// Call async method
var data = await FetchDataAsync();

Async with Cancellation

public async Task<string> DownloadAsync(CancellationToken ct)
{
    using var client = new HttpClient();
    var response = await client.GetAsync("https://api.example.com/file", ct);
    return await response.Content.ReadAsStringAsync(ct);
}

// Usage
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));

try
{
    var data = await DownloadAsync(cts.Token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Download cancelled");
}

Parallel Async

// Sequential
var result1 = await GetData1Async();
var result2 = await GetData2Async();

// Parallel
var (r1, r2) = await (GetData1Async(), GetData2Async());

// Task.WhenAll
var tasks = new[] { GetData1Async(), GetData2Async(), GetData3Async() };
var results = await Task.WhenAll(tasks);

// Task.WhenAny
var first = await Task.WhenAny(tasks);

async Main (C# 7.2+)

static async Task Main(string[] args)
{
    await DoWorkAsync();
}

Generics

Generic Class

public class Box<T>
{
    public T Content { get; set; }
}

var intBox = new Box<int> { Content = 42 };
var stringBox = new Box<string> { Content = "Hello" };

Generic Method

public static void Swap<T>(ref T a, ref T b)
{
    (a, b) = (b, a);
}

int x = 1, y = 2;
Swap(ref x, ref y);

Generic Constraints

// struct - value type
// class - reference type
// new() - parameterless constructor
// : BaseClass - must inherit
// : IInterface - must implement

public class DataStore<T> where T : class
{
    public T Data { get; set; }
}

public class Comparer<T> where T : IComparable<T>
{
    public bool IsGreater(T a, T b) => a.CompareTo(b) > 0;
}

public class Factory<T> where T : new()
{
    public T Create() => new T();
}

Covariance and Contravariance

// out - covariance (return type)
IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;  // IEnumerable<out T>

// in - contravariance (parameter type)
Action<Base> baseAction = (Base b) => { };
Action<Derived> derivedAction = baseAction;

Attributes

Basic Attribute

[Obsolete("Use NewMethod instead")]
public void OldMethod()
{
}

[Serializable]
public class User
{
    public string Name { get; set; }
}

[Range(1, 100)]
public int Quantity { get; set; }

[Required]
[EmailAddress]
public string Email { get; set; }

Custom Attribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DocumentationAttribute : Attribute
{
    public string Author { get; init; }
    public string Date { get; init; }
    public string Version { get; init; } = "1.0";
}

[Documentation(Author = "John", Date = "2024-01-01")]
public class MyClass
{
}

Reflection

var type = typeof(MyClass);
var attributes = type.GetCustomAttributes(typeof(DocumentationAttribute), true);

if (attributes.Length > 0)
{
    var doc = (DocumentationAttribute)attributes[0];
    Console.WriteLine($"Author: {doc.Author}");
}

Pattern Matching

Type Pattern

object obj = "Hello";

if (obj is string s)
{
    Console.WriteLine(s.Length);
}

// With not null
if (obj is string { Length: > 0 } s)
{
    Console.WriteLine(s);
}

Switch Expression

Shape GetShapeType(Shape shape) => shape switch
{
    Circle c => c,
    Rectangle r when r.Width == r.Height => new Square(r.Width),
    Rectangle r => r,
    _ => throw new ArgumentException()
};

Property Pattern

if (person is { Name: "John", Age: >= 18 })
{
    Console.WriteLine("Adult John");
}

var greeting = person switch
{
    { Name: "John" } => "Hello John",
    { Name: var n } => $"Hello {n}"
};

Tuple Pattern

string GetResult((int a, int b) pair) => pair switch
{
    (0, 0) => "Origin",
    (_, 0) => "X-axis",
    (0, _) => "Y-axis",
    (var x, var y) when x == y => "Diagonal",
    _ => "Other"
};

Testing

xUnit

using Xunit;

public class CalculatorTests
{
    [Fact]
    public void Add_TwoNumbers_ReturnsSum()
    {
        // Arrange
        var calculator = new Calculator();

        // Act
        int result = calculator.Add(2, 3);

        // Assert
        Assert.Equal(5, result);
    }

    [Theory]
    [InlineData(1, 2, 3)]
    [InlineData(0, 0, 0)]
    [InlineData(-1, 1, 0)]
    public void Add_VariousInputs_ReturnsExpected(int a, int b, int expected)
    {
        var calculator = new Calculator();
        Assert.Equal(expected, calculator.Add(a, b));
    }

    [Fact]
    public void Divide_ByZero_ThrowsException()
    {
        var calculator = new Calculator();
        Assert.Throws<DivideByZeroException>(() => calculator.Divide(1, 0));
    }
}

Setup/Teardown

public class DatabaseTests : IDisposable
{
    private Database _db;

    public DatabaseTests()
    {
        _db = new Database();
        _db.Connect();
    }

    public void Dispose()
    {
        _db.Disconnect();
    }

    [Fact]
    public void Test1()
    {
        // Uses fresh database
    }
}

Next Steps

Now that you know C# fundamentals:

  • Build web apps with ASP.NET Core
  • Create desktop apps with WPF or WinUI
  • Learn Blazor for web UI
  • Explore Unity for game development
  • Build cloud services with Azure

References

On this page

Table of contentsWhat is C#?Key CharacteristicsWhy learn C#?1. Wide Platform Support2. Rich Ecosystem3. Career Opportunities4. Game DevelopmentInstallation and Setup.NET SDKIDE OptionsCreating a ProjectRunningHello WorldVariables and Data TypesValue TypesReference Typesvar and Type InferenceConstantsNullable TypesDefault ValuesOperatorsArithmeticComparisonLogicalNull OperatorsTernaryFlow ControlIf/ElseSwitchFor LoopWhile LoopJump StatementsMethodsBasic MethodParametersLocal FunctionsExpression-bodied MembersStringsCreating StringsString MethodsString FormattingStringBuilderArraysCreating ArraysMulti-dimensionalJagged ArraysArray MethodsListsCreating ListsList MethodsCollectionsDictionaryHashSetQueueStackLinkedListLINQQuery SyntaxMethod SyntaxDeferred ExecutionClassesBasic ClassAccess ModifiersStatic MembersPartial ClassesInheritanceBasic InheritanceConstructor InheritanceSealed ClassesAbstract ClassesInterfacesBasic InterfaceInterface ImplementationDefault Interface Methods (C# 8+)RecordsBasic RecordClass-like RecordWith ExpressionsImmutabilityValue EqualityStructsBasic Structreadonly Structref StructException HandlingBasic Try/CatchThrowing ExceptionsCustom ExceptionsException Filters (C# 6+)File HandlingReading FilesWriting FilesFileInfoDirectory OperationsDelegates and EventsDelegatesGeneric DelegatesEventsCustom EventArgsAsync/AwaitBasic AsyncAsync with CancellationParallel Asyncasync Main (C# 7.2+)GenericsGeneric ClassGeneric MethodGeneric ConstraintsCovariance and ContravarianceAttributesBasic AttributeCustom AttributeReflectionPattern MatchingType PatternSwitch ExpressionProperty PatternTuple PatternTestingxUnitSetup/TeardownNext StepsReferences