CSharp Complete Guide
CSharp Complete Guide
Table of Contents
INTERMEDIATE
1. Refactoring
Refactoring means improving the structure of existing code without changing its behavior. It is not
rewriting — it is cleaning.
Why Refactor?
Code rots. What starts clean becomes tangled as features get added under pressure. Refactoring keeps
code readable, testable, and changeable.
Extract Method
When a block of code does one identifiable thing, extract it into its own method.
// BEFORE — hard to skim, long method doing too much
void ProcessOrder(Order order)
{
// Validate
if (order == null) throw new ArgumentNullException(nameof(order));
if ([Link] == 0) throw new InvalidOperationException("Order is empty.");
if ([Link] == null) throw new InvalidOperationException("No customer.");
// Calculate total
decimal total = 0;
foreach (var item in [Link])
total += [Link] * [Link];
if ([Link]) total *= 0.9m;
// Send confirmation
string message = $"Order confirmed. Total: {total:C}";
Page 1 of 77
C# Complete Developer Guide — Intermediate to Advanced
// AFTER
int daysUntilExpiry = 7;
bool IsAdult(int age) => age > 18;
List<int> eligibleUserIds = new List<int>();
Page 2 of 77
C# Complete Developer Guide — Intermediate to Advanced
// AFTER
const int SpeedLimitKph = 120;
const decimal DiscountRate = 0.15m;
// AFTER
int result = Compute(x);
Page 3 of 77
C# Complete Developer Guide — Intermediate to Advanced
ChargeCard(user, [Link]);
}
2. Enums
An enum is a named set of integer constants. Use them whenever a variable can only hold one of a fixed
set of meaningful values.
Basic Enum
public enum Direction
{
North, // = 0 (default)
South, // = 1
East, // = 2
West // = 3
}
if (heading == [Link])
[Link]("Heading north.");
Enum in Switch
public enum Season { Spring, Summer, Autumn, Winter }
Page 4 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Safe parse
if ([Link]<Direction>("West", out Direction result))
[Link](result);
// enum → string
[Link]([Link]()); // "South"
// All values
foreach (Direction dir in [Link]<Direction>())
[Link](dir);
3. Properties
Properties are class members that look like fields but execute code when read or written. They are the
C# way to implement encapsulation.
Auto-Properties
public class Person
{
public string Name { get; set; } // read + write
public int Age { get; private set; } // read anywhere, write only inside class
Page 5 of 77
C# Complete Developer Guide — Intermediate to Advanced
Page 6 of 77
C# Complete Developer Guide — Intermediate to Advanced
{
get => celsius;
set => celsius = value;
}
4. Multidimensional Arrays
C# supports both true multidimensional arrays ([,]) and jagged arrays ([][]). They serve different
purposes.
2D Array (Rectangular)
All rows have the same length. Stored in one contiguous block of memory.
// Declare and initialize
int[,] grid = new int[3, 4]; // 3 rows, 4 columns
// Access
grid[0, 0] = 10;
grid[2, 3] = 99;
// Iterate
for (int row = 0; row < [Link](0); row++)
{
for (int col = 0; col < [Link](1); col++)
{
[Link](grid[row, col] + "\t");
}
[Link]();
}
// Initialize inline
int[,] matrix = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
[Link](matrix[1, 2]); // 6
Page 7 of 77
C# Complete Developer Guide — Intermediate to Advanced
3D Array
int[,,] cube = new int[4, 4, 4]; // 4x4x4 cube
cube[0, 0, 0] = 1;
cube[3, 3, 3] = 64;
// Access
[Link](jagged[1][2]); // 5
5. Nested Loops
Nested loops are loops inside loops. Each iteration of the outer loop runs the entire inner loop.
Page 8 of 77
C# Complete Developer Guide — Intermediate to Advanced
Basic Pattern
// Multiplication table
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 5; j++)
{
[Link]($"{i * j,4}");
}
[Link]();
}
Performance Awareness
Nested loops multiply complexity. Two loops each running N times = O(N²). Watch for this in game
loops.
// O(N²) — acceptable for small N
for (int i = 0; i < [Link]; i++)
for (int j = i + 1; j < [Link]; j++)
CheckCollision(enemies[i], enemies[j]);
Page 9 of 77
C# Complete Developer Guide — Intermediate to Advanced
6. Recursion
Recursion is when a method calls itself. Every recursive solution needs a base case (the stop condition)
and a recursive case (the step toward the base).
[Link](Factorial(5)); // 120
// Stack: Factorial(5) → 5 * Factorial(4) → 5 * 4 * Factorial(3) → ...
Fibonacci
// Naive recursive — O(2^n), very slow for large n
int Fib(int n)
{
if (n <= 1) return n;
return Fib(n - 1) + Fib(n - 2);
}
// Memoized — O(n)
Dictionary<int, long> memo = new();
long FibMemo(int n)
{
if (n <= 1) return n;
if ([Link](n, out long cached)) return cached;
memo[n] = FibMemo(n - 1) + FibMemo(n - 2);
return memo[n];
}
Page 10 of 77
C# Complete Developer Guide — Intermediate to Advanced
7. Dictionary
Dictionary<TKey, TValue> stores key-value pairs. Lookup by key is O(1) on average thanks to hashing.
Basic Operations
var scores = new Dictionary<string, int>();
// Add
scores["Alice"] = 95;
scores["Bob"] = 88;
[Link]("Charlie", 72); // throws if key exists
// Read
int alice = scores["Alice"]; // throws if key missing
if ([Link]("Dave", out int dave))
[Link](dave); // safe read
// Update
scores["Alice"] = 100;
// Remove
[Link]("Bob");
// Check existence
bool hasAlice = [Link]("Alice");
// Iterate
foreach (var kvp in scores)
[Link]($"{[Link]}: {[Link]}");
Page 11 of 77
C# Complete Developer Guide — Intermediate to Advanced
Common Patterns
// Count occurrences of words
string[] words = "the cat sat on the mat".Split();
var freq = new Dictionary<string, int>();
Dictionary as a Cache
private Dictionary<int, PlayerStats> statsCache = new();
Page 12 of 77
C# Complete Developer Guide — Intermediate to Advanced
Performance
Characteristics
Operation
Average
Worst
Add
O(1)
O(n) — resize
Lookup
O(1)
O(n) — hash collision
Remove
O(1)
O(n)
Iteration
O(n)
O(n)
8. Other Collections
Beyond List<T> and Dictionary<TKey,TValue>, the standard library provides specialized collections for
specific problems.
[Link]("Home");
[Link]("Products");
[Link]("Cart");
Page 13 of 77
C# Complete Developer Guide — Intermediate to Advanced
[Link]("[Link]");
[Link]("[Link]");
[Link]("[Link]");
[Link]("page1");
[Link]("page2");
[Link]("page1"); // ignored — already exists
[Link]([Link]); // 2
// Set operations
var setA = new HashSet<int> { 1, 2, 3, 4 };
var setB = new HashSet<int> { 3, 4, 5, 6 };
[Link](setB); // {1,2,3,4,5,6}
[Link](setB); // {3,4}
[Link](setB); // {1,2}
Page 14 of 77
C# Complete Developer Guide — Intermediate to Advanced
Page 15 of 77
C# Complete Developer Guide — Intermediate to Advanced
LinkedList<T>
9. params
The params keyword lets a method accept a variable number of arguments as an array, without the
caller needing to create an array explicitly.
int Sum(params int[] numbers)
{
return [Link]();
}
Real-World Use
// String formatting
string Format(string template, params object[] args)
=> [Link](template, args);
// Builder pattern
QueryBuilder Where(string field, params object[] values) { ... }
Page 16 of 77
C# Complete Developer Guide — Intermediate to Advanced
Named Arguments
Named arguments let you pass values out of order, which improves readability.
void DrawRect(int x, int y, int width, int height, string color = "black") { }
Rules
Optional parameters must appear after required ones
Default values must be compile-time constants (no new, no method calls)
When overriding methods, optional parameter defaults in the base class are used by callers
// Valid defaults
void Foo(int x = 0, string s = "hello", bool b = false, MyEnum e = MyEnum.A) { }
// Invalid defaults
// void Bar(List<int> list = new List<int>()) { } ERROR — not a constant
// void Baz(int x = SomeMethod()) { } ERROR — not a constant
Page 17 of 77
C# Complete Developer Guide — Intermediate to Advanced
Value Types in C
// All of these are value types:
int, long, short, byte // Integer types
float, double, decimal // Floating point
bool // Boolean
char // Character
struct // Any struct
enum // Any enum
DateTime, TimeSpan // Common structs
(int x, int y) // Tuples of value types
Reference Types in C
// All of these are reference types:
class // Any class
interface // References to interface implementations
string // Special — immutable reference type
array // int[], string[], etc.
delegate // Action, Func, etc.
object // The root type
Null Behavior
Value types cannot be null by default. Reference types can.
int x = null; // COMPILE ERROR
string s = null; // OK — null reference
object o = null; // OK
Page 18 of 77
C# Complete Developer Guide — Intermediate to Advanced
Passing to Methods
// Value type — method gets its own copy
void Double(int x) { x *= 2; }
int n = 5;
Double(n);
[Link](n); // 5 — unchanged
12. Struct
A struct is a value type that groups related data. Perfect for small, lightweight data that is frequently
copied.
Declaring a Struct
public struct Point
{
public float X;
public float Y;
Page 19 of 77
C# Complete Developer Guide — Intermediate to Advanced
Page 20 of 77
C# Complete Developer Guide — Intermediate to Advanced
Page 21 of 77
C# Complete Developer Guide — Intermediate to Advanced
Static Members
Static members belong to the type, not to any instance.
public class Counter
{
private static int totalCount = 0; // shared across ALL instances
private int instanceId;
public Counter()
{
totalCount++;
instanceId = totalCount;
}
Nested Classes
Classes can be nested inside other classes. Useful for implementation details.
public class LinkedList<T>
{
// Private nested class — implementation detail
private class Node
{
public T Value;
public Node? Next;
public Node(T value) { Value = value; }
}
Page 22 of 77
C# Complete Developer Guide — Intermediate to Advanced
count++;
}
Page 23 of 77
C# Complete Developer Guide — Intermediate to Advanced
14. Interfaces
An interface defines a contract — a set of members that implementing types must provide. No
implementation, no fields, no constructors.
Page 24 of 77
C# Complete Developer Guide — Intermediate to Advanced
Interface Segregation
Keep interfaces focused. A class implementing an interface should need ALL its members.
// BAD — too broad
public interface IWorker
{
void Work();
void Eat();
void Sleep();
void ManageTeam();
}
// GOOD — segregated
public interface IWorkable { void Work(); }
public interface IManageable { void ManageTeam(); }
Page 25 of 77
C# Complete Developer Guide — Intermediate to Advanced
if (s != null)
[Link]([Link]());
Page 26 of 77
C# Complete Developer Guide — Intermediate to Advanced
Switch Expression
// Traditional switch statement
string msg;
switch (day)
{
case [Link]:
case [Link]:
msg = "Weekend"; break;
default:
msg = "Weekday"; break;
}
Page 27 of 77
C# Complete Developer Guide — Intermediate to Advanced
_ => "Weekday"
};
Type Patterns
string Describe(object obj) => obj switch
{
int n when n < 0 => $"Negative int: {n}",
int n => $"Positive int: {n}",
string s => $"String: '{s}'",
null => "null",
_ => $"Something else: {[Link]().Name}"
};
Property Patterns
public record Order(decimal Total, bool IsVip, string Status);
Tuple Patterns
string RPS(string player1, string player2) => (player1, player2) switch
{
("Rock", "Scissors") => "Player 1 wins",
("Paper", "Rock") => "Player 1 wins",
("Scissors", "Paper") => "Player 1 wins",
var (a, b) when a == b => "Draw",
_ => "Player 2 wins"
};
17. Delegates
A delegate is a type-safe reference to a method. It defines the signature a method must have to be
referenced.
Page 28 of 77
C# Complete Developer Guide — Intermediate to Advanced
op = Multiply;
[Link](op(3, 4)); // 12
greet(); // Hello!
greetUser("Alice"); // Hello, Alice!
printSum(3, 4); // 7
[Link](add(3, 4)); // 7
[Link](isLong("hi")); // False
Multicast Delegates
A delegate variable can reference multiple methods. All are called when the delegate is invoked.
Action<string> log = msg => [Link]("[Console] " + msg);
log += msg => [Link]("[Link]", msg + "\n"); // also log to file
log += msg => [Link]("[Debug] " + msg);
Page 29 of 77
C# Complete Developer Guide — Intermediate to Advanced
onMatch(n);
}
Lambda Expressions
Compact, expression-based, often used inline.
// Inline in LINQ
var evens = [Link](n => n % 2 == 0).ToList();
// Assigned to a variable
Func<int, int> square = x => x * x;
Func<int, int, int> add = (a, b) => a + b;
// Multi-line lambda
Func<int, string> classify = n =>
{
if (n < 0) return "negative";
if (n == 0) return "zero";
return "positive";
};
Local Functions
Named methods defined inside another method. Better for recursion, clearer for multi-line logic.
List<int> GetPrimes(int max)
{
var primes = new List<int>();
return primes;
Page 30 of 77
C# Complete Developer Guide — Intermediate to Advanced
bool IsPrime(int n)
{
for (int i = 2; i <= [Link](n); i++)
if (n % i == 0) return false;
return true;
}
}
Local function:
- Multi-line, complex logic
- When the helper is recursive
- Better debuggability (named in stack traces)
- When you want static (preventing closure capture)
// Local function with static keyword — cannot capture outer variables
// Prevents accidental captures, slightly more performant
int OuterValue = 10;
19. Events
Events are a publisher-subscriber mechanism built on top of delegates. They enforce that only the
owning class can invoke them.
Page 31 of 77
C# Complete Developer Guide — Intermediate to Advanced
{
text = value;
TextChanged?.Invoke(value); // Only Button can raise this
}
}
}
// Subscribe
[Link] += OnButtonClicked;
[Link] += (newText) => [Link]($"Text: {newText}");
void OnButtonClicked()
{
[Link]("Button was clicked!");
}
Page 32 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Subscriber
var service = new OrderService();
[Link] += (sender, e) =>
{
[Link]($"Order {[Link]} placed! Total: {[Link]:C}");
};
20. Generics
Generics let you write type-safe code that works with any type, decided at compile time without boxing
overhead.
Generic Methods
// Without generics — one method per type, or uses object (boxing)
void SwapInt(ref int a, ref int b) { int tmp = a; a = b; b = tmp; }
void SwapString(ref string a, ref string b) { string tmp = a; a = b; b = tmp; }
Page 33 of 77
C# Complete Developer Guide — Intermediate to Advanced
int x = 1, y = 2;
Swap(ref x, ref y); // T inferred as int
[Link]($"{x}, {y}"); // 2, 1
Generic Classes
public class Result<T>
{
public bool IsSuccess { get; }
public T? Value { get; }
public string? Error { get; }
Result<int> Parse(string s)
{
if ([Link](s, out int n))
return Result<int>.Success(n);
return Result<int>.Failure($"'{s}' is not a number");
}
Generic Constraints
// T must implement IComparable<T>
T Max<T>(T a, T b) where T : IComparable<T>
=> [Link](b) >= 0 ? a : b;
Page 34 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Multiple constraints
T Create<T>() where T : class, IDisposable, new() => new T();
Generic Interfaces
public interface IRepository<T> where T : class
{
T? GetById(int id);
IEnumerable<T> GetAll();
void Add(T entity);
void Update(T entity);
void Delete(int id);
}
const
Replaced by the literal value at compile time. Must be a primitive type or string.
public class MathConstants
{
Page 35 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Usage
double area = [Link] * r * r;
readonly
Assigned once at runtime — either when declared or in the constructor. Works with any type.
public class Config
{
public readonly string ConnectionString;
public readonly DateTime StartTime = [Link]; // set at declaration
public readonly List<string> AllowedRoles; // reference type is OK
Page 36 of 77
C# Complete Developer Guide — Intermediate to Advanced
const vs readonly
Comparison
Feature
const
readonly
Set when
Compile time
Constructor or declaration
Types allowed
Primitives, string
Any type
Memory
Inlined as literal
Stored in memory
static
Implicitly static
Can be instance or static
Use for
Math constants, config keys
Runtime-determined values
Page 37 of 77
C# Complete Developer Guide — Intermediate to Advanced
Basic Try/Catch
try
{
int[] arr = { 1, 2, 3 };
[Link](arr[10]); // Throws IndexOutOfRangeException
}
catch (IndexOutOfRangeException ex)
{
[Link]($"Array error: {[Link]}");
}
catch (Exception ex) // Catches any remaining exception
{
[Link]($"Unexpected error: {[Link]}");
}
finally
{
// Always runs — cleanup code goes here
[Link]("Done.");
}
Custom Exceptions
public class InsufficientFundsException : Exception
{
public decimal Amount { get; }
Page 38 of 77
C# Complete Developer Guide — Intermediate to Advanced
balance -= amount;
}
}
// Caller
try
{
[Link](1000);
}
catch (InsufficientFundsException ex)
{
[Link]($"Denied. You need {[Link] - [Link]:C} more.");
}
Page 39 of 77
C# Complete Developer Guide — Intermediate to Advanced
23. IEnumerable
IEnumerable<T> is the interface for any sequence you can iterate with foreach. It is the foundation of
LINQ.
// Translates to this:
IEnumerator<int> enumerator = [Link]();
while ([Link]())
[Link]([Link]);
Page 40 of 77
C# Complete Developer Guide — Intermediate to Advanced
if (i % 2 == 0)
yield return i;
}
[Link] [Link]()
=> GetEnumerator(); // Non-generic version required
}
24. Namespaces
Namespaces organize code into logical groups and prevent naming conflicts.
Page 41 of 77
C# Complete Developer Guide — Intermediate to Advanced
Declaring Namespaces
namespace [Link]
{
public class UserRepository
{
// ...
}
}
namespace [Link]
{
public class UserService
{
// ...
}
}
Using Directives
using System;
using [Link];
using [Link];
Page 42 of 77
C# Complete Developer Guide — Intermediate to Advanced
Basic Implementation
public class GameSettings
{
private static GameSettings? instance;
private static readonly object lockObj = new();
// Usage
Page 43 of 77
C# Complete Developer Guide — Intermediate to Advanced
[Link] = 0.5f;
[Link]([Link]);
private AppConfig() { }
Page 44 of 77
C# Complete Developer Guide — Intermediate to Advanced
}
}
Creational Patterns
Factory Method — define an interface for creating objects; subclasses decide which to instantiate.
public abstract class Notification
{
public abstract void Send(string message);
// Factory method
public static Notification Create(string type) => type switch
{
"email" => new EmailNotification(),
"sms" => new SmsNotification(),
"push" => new PushNotification(),
_ => throw new ArgumentException($"Unknown type: {type}")
};
}
Notification n = [Link]("email");
[Link]("Hello!");
Builder — construct complex objects step by step.
var email = new EmailBuilder()
.To("alice@[Link]")
.Subject("Welcome")
.Body("Hello, Alice!")
.WithAttachment("[Link]")
.Build();
Structural Patterns
Decorator — add behavior to objects without subclassing.
public interface IDataSource { string Read(); void Write(string data); }
Page 45 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Stack decorators
IDataSource source = new EncryptionDecorator(
new CompressionDecorator(
new FileDataSource("[Link]")
)
);
[Link]("sensitive data");
Behavioral Patterns
Observer — notify dependents when state changes (see Events section).
Strategy — define family of algorithms, make them interchangeable.
Page 46 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Undo/redo system
var history = new Stack<ICommand>();
void Do(ICommand cmd) { [Link](); [Link](cmd); }
void UndoLast() { if ([Link] > 0) [Link]().Undo(); }
ADVANCED
27. Reflection
Reflection allows code to inspect and interact with its own types at runtime — reading metadata,
invoking methods by name, creating instances dynamically.
Inspecting Types
using [Link];
[Link]([Link]); // String
[Link]([Link]); // System
[Link]([Link]); // True
// From assembly
Assembly assembly = [Link]();
Page 47 of 77
C# Complete Developer Guide — Intermediate to Advanced
Page 48 of 77
C# Complete Developer Guide — Intermediate to Advanced
Extending Collections
public static class CollectionExtensions
{
public static bool IsNullOrEmpty<T>(this ICollection<T>? collection)
=> collection == null || [Link] == 0;
Page 49 of 77
C# Complete Developer Guide — Intermediate to Advanced
}
}
Extending Interfaces
This is particularly powerful — you can add behavior to ALL implementations of an interface.
public static class RepositoryExtensions
{
public static bool Exists<T>(this IRepository<T> repo, int id) where T : class
=> [Link](id) != null;
ConnectionString = [Link]("DB_CONNECTION")
?? "Server=localhost;Database=app;";
ApiKey = [Link]("[Link]")
? [Link]("[Link]").Trim()
: throw new InvalidOperationException("[Link] file missing");
Page 50 of 77
C# Complete Developer Guide — Intermediate to Advanced
["locale"] = "en-US"
};
}
}
Rules
Runs automatically before first access to any static member or instance creation
No parameters, no access modifier
Only one per class
Cannot be called manually
Exceptions in static constructors cause TypeInitializationException
Page 51 of 77
C# Complete Developer Guide — Intermediate to Advanced
// In generics
T GetDefault<T>() => default(T);
// Or simply:
T GetDefault<T>() => default; // C# 7.1+
Page 52 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Expression-bodied property
public string FullName => $"{FirstName} {LastName}";
// Expression-bodied method
public string Greet() => $"Hello, I'm {FullName}.";
// Expression-bodied override
public override string ToString() => FullName;
}
Page 53 of 77
C# Complete Developer Guide — Intermediate to Advanced
32. Records
Records (C# 9+) are classes or structs designed for immutable data with built-in equality, hashing, and
string representation.
Record Class
// This single line generates:
// - Constructor, properties
// - Equals(), GetHashCode(), ToString()
// - With expression support
public record Point(double X, double Y);
Record vs Class
// Class equality = reference equality (same object)
var c1 = new PersonClass("Alice", 30);
var c2 = new PersonClass("Alice", 30);
[Link](c1 == c2); // False — different objects
Page 54 of 77
C# Complete Developer Guide — Intermediate to Advanced
// On collections
string? first = list?[0]; // null if list is null
int? count = list?.Count; // null if list is null
Null-Coalescing Operator ??
Returns the left side if not null, otherwise the right side.
string name = [Link] ?? "Anonymous";
int timeout = [Link] ?? 30;
var items = GetItems() ?? new List<string>();
// Chained
string val = a ?? b ?? c ?? "default";
// Old way
if (cache == null) cache = new List<string>();
// New way
cache ??= new List<string>();
Page 55 of 77
C# Complete Developer Guide — Intermediate to Advanced
Combining Them
// Without null operators
string displayName;
if (user != null && [Link] != null && [Link] != null)
displayName = [Link];
else
displayName = "Guest";
// In method arguments
[Link](count == 1 ? "1 item" : $"{count} items");
// Null checks
string name = user != null ? [Link] : "Unknown";
// Better with ?? if result is about null fallback:
string name2 = user?.Name ?? "Unknown";
// Checking
if ([Link])
[Link]([Link]);
// Coalescing
int value = x ?? 0;
Page 56 of 77
C# Complete Developer Guide — Intermediate to Advanced
// GetValueOrDefault
int v = [Link](); // 0 if null
int v2 = [Link](99); // 99 if null
36. Span
Span<T> is a stack-allocated, array-like type for high-performance slicing of memory without allocations.
Basic Usage
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8 };
Page 57 of 77
C# Complete Developer Guide — Intermediate to Advanced
middle[0] = 99;
[Link](array[2]); // 99 — same memory
Why Span?
// Without Span — allocates new string
string input = "2024-01-15";
string year = [Link](0, 4); // NEW string allocation
string month = [Link](5, 2); // NEW string allocation
Span Limitations
Cannot be stored in heap fields (class members)
Cannot be used with async/await
Cannot be boxed
Designed for synchronous, stack-based processing
The Operators
int a = 0b1010; // 10
int b = 0b1100; // 12
Page 58 of 77
C# Complete Developer Guide — Intermediate to Advanced
Practical Uses
// Fast multiply/divide by powers of 2
int x = 8;
int doubled = x << 1; // 16 — faster than x * 2 on some platforms
int halved = x >> 1; // 4
Page 59 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Add a flag
userPerms |= [Link];
// Remove a flag
userPerms &= ~[Link];
// Toggle a flag
userPerms ^= [Link];
// Conditional compilation
#if DEBUG_MODE
[Link]("Debug build — extra logging enabled.");
#elif RELEASE
[Link]("Release build.");
#else
[Link]("Unknown build.");
#endif
#if UNITY_EDITOR
// Unity editor-only code
#endif
// Platform-specific
#if WINDOWS
// Windows code
#elif LINUX
// Linux code
#endif
// Suppress warnings
#pragma warning disable CS0168 // Unused variable
Page 60 of 77
C# Complete Developer Guide — Intermediate to Advanced
int unused;
#pragma warning restore CS0168
int n = 5;
Double(ref n);
[Link](n); // 10 — modified
Page 61 of 77
C# Complete Developer Guide — Intermediate to Advanced
in — Read-Only Reference
Passes a reference (no copy) but prevents modification. Performance optimization for large structs.
// Without in — copies 64 bytes on each call
double CalculateDot(Vector4 a, Vector4 b)
=> a.X*b.X + a.Y*b.Y + a.Z*b.Z + a.W*b.W;
Hidden Boxing
// ArrayList boxes every value type (legacy)
[Link] list = new();
[Link](42); // BOXES int
[Link](3.14); // BOXES double
Page 62 of 77
C# Complete Developer Guide — Intermediate to Advanced
Avoiding Boxing
// Use generic collections — no boxing
List<int> nums = new();
[Link](42); // No boxing
42. dynamic
dynamic bypasses compile-time type checking. Resolved at runtime by the Dynamic Language Runtime
(DLR).
dynamic x = 10;
[Link](x + 5); // 15 (int)
x = "hello";
[Link]([Link]); // 5 (string) — no compile error
x = new List<int> { 1, 2, 3 };
[Link](4); // Works at runtime — no intellisense though
Practical Uses
// Working with COM objects (Office interop)
dynamic excel = [Link]([Link]("[Link]")!);
[Link] = true;
Page 63 of 77
C# Complete Developer Guide — Intermediate to Advanced
Caution
dynamic loses IntelliSense, refactoring support, and compile-time safety. Use it only when you genuinely
don’t know the type (interop, serialization, scripting). For normal C# code, use proper types or generics.
43. Attributes
Attributes attach metadata to types, methods, and members. They are read at runtime via reflection, or
at compile time by source generators.
Built-In Attributes
[Obsolete("Use NewMethod() instead.", error: false)]
void OldMethod() { } // Warning when called
[Serializable]
class SaveData { } // Marks for binary serialization
[NonSerialized]
private int runtimeCache; // Exclude from serialization
[Conditional("DEBUG")]
void LogDebug(string msg) // Only compiled in DEBUG builds
=> [Link](msg);
[ThreadStatic]
private static int threadLocalValue; // Separate copy per thread
Custom Attributes
// Define an attribute
[AttributeUsage([Link] | [Link],
AllowMultiple = false,
Inherited = true)]
public class AuthorAttribute : Attribute
{
public string Name { get; }
public string Email { get; }
public int Year { get; set; }
Page 64 of 77
C# Complete Developer Guide — Intermediate to Advanced
44. Tuples
Tuples group multiple values without creating a named type.
// Unnamed tuple
var point = (3, 4);
[Link](point.Item1); // 3
[Link](point.Item2); // 4
// Named tuple
var person = (Name: "Alice", Age: 30);
[Link]([Link]); // Alice
[Link]([Link]); // 30
Page 65 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Multiple resources
using var conn = new SqlConnection(connectionString);
using var cmd = new SqlCommand("SELECT ...", conn);
// Both disposed at end of scope
Implementing IDisposable
public class DatabaseConnection : IDisposable
{
private SqlConnection? connection;
private bool disposed;
Page 66 of 77
C# Complete Developer Guide — Intermediate to Advanced
if (!disposed)
{
if (disposing)
{
connection?.Close();
connection?.Dispose();
connection = null;
}
disposed = true;
}
}
}
46. LINQ
Language Integrated Query lets you query collections using a fluent, SQL-like syntax directly in C#.
Method Syntax
var nums = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Filter
var evens = [Link](n => n % 2 == 0);
// Transform
var squares = [Link](n => n * n);
// Filter + transform
var result = nums
.Where(n => n > 3)
.Select(n => n * 2)
.ToList();
// Aggregate
int sum = [Link]();
double avg = [Link]();
int max = [Link]();
int min = [Link]();
// First/Single
int first = [Link]();
int firstEven = [Link](n => n % 2 == 0);
Page 67 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Sorting
var sorted = [Link](n => n);
var sortedDesc = [Link](n => n);
// Any / All
bool anyNegative = [Link](n => n < 0); // False
bool allPositive = [Link](n => n > 0); // True
// GroupBy
var people = new List<(string Name, string City)>
{
("Alice", "NYC"), ("Bob", "LA"), ("Carol", "NYC")
};
// Join
var orders = [Link](
invoices,
customer => [Link],
invoice => [Link],
(customer, invoice) => new { [Link], [Link] }
);
Query Syntax
var result =
from n in nums
where n % 2 == 0
orderby n descending
select n * 10;
// Equivalent to:
var result2 = nums
.Where(n => n % 2 == 0)
Page 68 of 77
C# Complete Developer Guide — Intermediate to Advanced
.OrderByDescending(n => n)
.Select(n => n * 10);
// Arithmetic
public static Money operator +(Money a, Money b)
{
if ([Link] != [Link])
throw new InvalidOperationException("Cannot add different currencies.");
return new Money([Link] + [Link], [Link]);
}
Page 69 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Implicit/explicit conversions
public static implicit operator decimal(Money m) => [Link];
public static explicit operator Money(decimal amount) => new Money(amount, "USD");
Page 70 of 77
C# Complete Developer Guide — Intermediate to Advanced
// Returns a value
async Task<string> GetDataAsync()
{
await [Link](1000); // Simulate network call
return "Some data";
}
// Chaining
async Task MainAsync()
{
string data = await GetDataAsync(); // Waits, then assigns
[Link](data);
try
{
HttpResponseMessage response = await [Link](url);
[Link]();
Page 71 of 77
C# Complete Developer Guide — Intermediate to Advanced
}
}
CancellationToken
async Task LongOperation(CancellationToken ct)
{
for (int i = 0; i < 100; i++)
{
[Link](); // Check at safe points
await [Link](100, ct); // Cancellable delay
[Link]($"Step {i}");
}
}
try
{
await LongOperation([Link]);
}
catch (OperationCanceledException)
{
[Link]("Operation was cancelled.");
}
Page 72 of 77
C# Complete Developer Guide — Intermediate to Advanced
49. Multithreading
Multithreading lets multiple pieces of code run concurrently on different CPU cores.
Thread Basics
void PrintNumbers()
{
for (int i = 0; i < 5; i++)
{
[Link]($"Thread {[Link]}: {i}");
[Link](100);
}
}
[Link]();
[Link]();
void SafeIncrement()
{
for (int i = 0; i < 100000; i++)
{
lock (lockObj) { counter++; }
}
}
// Now counter is always 200000
Page 73 of 77
C# Complete Developer Guide — Intermediate to Advanced
await t;
// [Link]
[Link](items, item => Process(item));
Page 74 of 77
C# Complete Developer Guide — Intermediate to Advanced
Page 75 of 77
C# Complete Developer Guide — Intermediate to Advanced
Page 76 of 77
C# Complete Developer Guide — Intermediate to Advanced
Rules to Live By
Name everything clearly — code is read 10× more than it is written
Fail fast — validate inputs immediately, throw early
Prefer immutability — readonly, init, record
Avoid boxing — use generics, not object
Always unsubscribe events — or use WeakReference patterns
Dispose IDisposable — always use using
Async all the way — don’t mix sync and async without .GetAwaiter().GetResult()
Lock narrow — hold locks for the minimum time possible
Test pure functions — separate logic from I/O, test logic in isolation
Let the compiler help — enable nullable, use readonly, use const — the compiler is your ally
Page 77 of 77