C#

Essential C# syntax, features, and best practices for .NET development.

languages
csharpdotnetoopmicrosoft

Variables & Data Types

// Value types
int number = 42;
double price = 19.99;
bool isActive = true;
char letter = 'A';
decimal money = 100.50m;

// Reference types
string name = "Hello";
object obj = new object();

// Nullable types
int? nullableInt = null;

// Type inference
var message = "Inferred as string";

// Constants
const double PI = 3.14159;
readonly string readOnlyField = "Can only be set in constructor";

Strings

// String interpolation
string name = "World";
string greeting = $"Hello, {name}!";

// Verbatim strings (ignore escape sequences)
string path = @"C:\Users\Documents";

// Raw string literals (C# 11+)
string json = """
    {
        "name": "John",
        "age": 30
    }
    """;

// Common string methods
string text = "Hello World";
text.ToUpper();          // "HELLO WORLD"
text.ToLower();          // "hello world"
text.Trim();             // Remove whitespace
text.Split(' ');         // ["Hello", "World"]
text.Contains("World");  // true
text.Replace("World", "C#");
text.Substring(0, 5);    // "Hello"

Arrays & Collections

// Arrays
int[] numbers = { 1, 2, 3, 4, 5 };
int[] zeros = new int[10];
string[,] matrix = new string[3, 3];

// List
List<string> names = new List<string> { "Alice", "Bob" };
names.Add("Charlie");
names.Remove("Bob");
names.Contains("Alice");  // true

// Dictionary
Dictionary<string, int> ages = new Dictionary<string, int>
{
    ["Alice"] = 30,
    ["Bob"] = 25
};
ages.TryGetValue("Alice", out int age);

// HashSet
HashSet<int> uniqueNumbers = new HashSet<int> { 1, 2, 3 };

// Queue and Stack
Queue<string> queue = new Queue<string>();
queue.Enqueue("first");
string item = queue.Dequeue();

Stack<string> stack = new Stack<string>();
stack.Push("first");
string top = stack.Pop();

Control Flow

// If-else
if (condition)
{
    // code
}
else if (otherCondition)
{
    // code
}
else
{
    // code
}

// Switch expression (C# 8+)
string result = day switch
{
    "Monday" => "Start of week",
    "Friday" => "End of week",
    _ => "Mid week"
};

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

// Switch with patterns
string message = shape switch
{
    Circle { Radius: > 10 } => "Large circle",
    Rectangle { Width: var w, Height: var h } when w == h => "Square",
    _ => "Unknown shape"
};

Loops

// For loop
for (int i = 0; i < 10; i++)
{
    Console.WriteLine(i);
}

// Foreach loop
foreach (var item in collection)
{
    Console.WriteLine(item);
}

// While loop
while (condition)
{
    // code
}

// Do-while loop
do
{
    // code
} while (condition);

Methods

// Basic method
public int Add(int a, int b)
{
    return a + b;
}

// Expression-bodied method
public int Multiply(int a, int b) => a * b;

// Optional parameters
public void Greet(string name, string greeting = "Hello")
{
    Console.WriteLine($"{greeting}, {name}!");
}

// Named arguments
Greet(greeting: "Hi", name: "Alice");

// Out parameters
public bool TryParse(string input, out int result)
{
    return int.TryParse(input, out result);
}

// Params array
public int Sum(params int[] numbers)
{
    return numbers.Sum();
}

// Ref parameters
public void Swap(ref int a, ref int b)
{
    (a, b) = (b, a);
}

Classes & Objects

// Class definition
public class Person
{
    // Fields
    private string _name;
    
    // Properties
    public string Name
    {
        get => _name;
        set => _name = value ?? throw new ArgumentNullException();
    }
    
    // Auto-property
    public int Age { get; set; }
    
    // Read-only property
    public string Id { get; } = Guid.NewGuid().ToString();
    
    // Constructor
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    
    // Method
    public void Introduce()
    {
        Console.WriteLine($"Hi, I'm {Name}");
    }
}

// Object initialization
var person = new Person("Alice", 30);
var person2 = new Person("Bob", 25) { Age = 26 };

Records (C# 9+)

// Record for immutable data
public record Person(string Name, int Age);

// With expression for copying with modifications
var person = new Person("Alice", 30);
var older = person with { Age = 31 };

// Record struct (C# 10+)
public record struct Point(int X, int Y);

Inheritance & Interfaces

// Interface
public interface IDrawable
{
    void Draw();
    double Area { get; }
}

// Abstract class
public abstract class Shape
{
    public abstract double CalculateArea();
    
    public virtual void Display()
    {
        Console.WriteLine("Shape");
    }
}

// Inheritance
public class Circle : Shape, IDrawable
{
    public double Radius { get; set; }
    
    public double Area => Math.PI * Radius * Radius;
    
    public override double CalculateArea() => Area;
    
    public void Draw()
    {
        Console.WriteLine("Drawing circle");
    }
}

LINQ

var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Query syntax
var evenQuery = from n in numbers
                where n % 2 == 0
                select n;

// Method syntax
var evenMethod = numbers.Where(n => n % 2 == 0);

// Common LINQ methods
numbers.Where(n => n > 5);           // Filter
numbers.Select(n => n * 2);          // Transform
numbers.OrderBy(n => n);             // Sort ascending
numbers.OrderByDescending(n => n);   // Sort descending
numbers.First();                     // First element
numbers.FirstOrDefault();            // First or default
numbers.Any(n => n > 5);             // Check if any match
numbers.All(n => n > 0);             // Check if all match
numbers.Count();                     // Count elements
numbers.Sum();                       // Sum values
numbers.Average();                   // Average value
numbers.GroupBy(n => n % 2);         // Group by key
numbers.Take(3);                     // Take first 3
numbers.Skip(3);                     // Skip first 3
numbers.Distinct();                  // Remove duplicates

Async/Await

// Async method
public async Task<string> FetchDataAsync(string url)
{
    using var client = new HttpClient();
    return await client.GetStringAsync(url);
}

// Async with multiple tasks
public async Task ProcessAllAsync()
{
    var task1 = FetchDataAsync("url1");
    var task2 = FetchDataAsync("url2");
    
    // Wait for all
    await Task.WhenAll(task1, task2);
    
    // Wait for any
    await Task.WhenAny(task1, task2);
}

// Async streams (C# 8+)
public async IAsyncEnumerable<int> GenerateNumbersAsync()
{
    for (int i = 0; i < 10; i++)
    {
        await Task.Delay(100);
        yield return i;
    }
}

Exception Handling

try
{
    // Code that might throw
    int result = int.Parse("not a number");
}
catch (FormatException ex)
{
    Console.WriteLine($"Format error: {ex.Message}");
}
catch (Exception ex) when (ex.Message.Contains("specific"))
{
    // Exception filter
    Console.WriteLine("Specific exception");
}
finally
{
    // Always executes
    Console.WriteLine("Cleanup");
}

// Throw exception
throw new InvalidOperationException("Something went wrong");

// Custom exception
public class CustomException : Exception
{
    public CustomException(string message) : base(message) { }
}

Null Handling

// Null-conditional operator
string? name = person?.Name;
int? length = name?.Length;

// Null-coalescing operator
string displayName = name ?? "Unknown";

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

// Null-forgiving operator
string definitelyNotNull = maybeNull!;

// Required members (C# 11+)
public class Person
{
    public required string Name { get; init; }
}

Generics

// Generic class
public class Container<T>
{
    public T Value { get; set; }
    
    public Container(T value)
    {
        Value = value;
    }
}

// Generic method
public T GetDefault<T>() where T : new()
{
    return new T();
}

// Generic constraints
public class Repository<T> where T : class, IEntity, new()
{
    public T Create() => new T();
}

Delegates & Events

// Delegate
public delegate void MessageHandler(string message);

// Using built-in delegates
Action<string> action = msg => Console.WriteLine(msg);
Func<int, int, int> add = (a, b) => a + b;
Predicate<int> isEven = n => n % 2 == 0;

// Events
public class Publisher
{
    public event EventHandler<string>? MessageReceived;
    
    protected virtual void OnMessageReceived(string message)
    {
        MessageReceived?.Invoke(this, message);
    }
}

// Subscribe to event
publisher.MessageReceived += (sender, msg) => Console.WriteLine(msg);

File I/O

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

// Write all text
File.WriteAllText("file.txt", "content");

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

// Async file operations
string content = await File.ReadAllTextAsync("file.txt");
await File.WriteAllTextAsync("file.txt", "content");

// Using StreamReader/StreamWriter
using var reader = new StreamReader("file.txt");
string line = await reader.ReadLineAsync();

using var writer = new StreamWriter("file.txt");
await writer.WriteLineAsync("Hello");

Common Attributes

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

// Serialization
[Serializable]
public class Data { }

// JSON serialization (System.Text.Json)
public class Person
{
    [JsonPropertyName("full_name")]
    public string Name { get; set; }
    
    [JsonIgnore]
    public string Secret { get; set; }
}