C# Quick Start
14 days from zero to reading and writing mid-sized C# programs. Aimed at learners with some programming background, this fast track covers core sophomore-level topics: types, control flow, methods, OOP, generics, LINQ, exceptions and files.
Meet C# and .NET
Start from Hello World and understand C# compilation and execution
C# is a strongly typed, object-oriented modern language that runs on the .NET platform. Understanding its execution chain matters:
source (.cs)→ C# compiler →IL(Intermediate Language, assembly .dll/.exe)IL→ CLR's JIT just-in-time compilation → machine code execution- The CLR (Common Language Runtime) handles memory management (GC), type safety, exceptions, etc.
Classic program structure: namespace → class → Main method (entry point). C# 9+ supports top-level statements, letting you omit Main and class — file-level code runs directly. Great for beginners.
using System;
namespace HelloApp
{
class Program
{
static void Main()
{
Console.WriteLine("Hello, C#!");
int a = 10, b = 20;
Console.WriteLine($"a + b = {a + b}");
}
}
}
// C# 9+ top-level statements: omit Main and class
using System;
Console.WriteLine("Hello, C#!");
int a = 10, b = 20;
Console.WriteLine($"a + b = {a + b}");
a + b = 30
using System; imports a namespace; Console.WriteLine prints a line; $"..." is string interpolation, where {expression} is replaced by its value. Q1What is the intermediate product after the C# compiler runs?
- A Machine code
- B IL (Intermediate Language)
- C Java bytecode
- D Assembly code
Q2What is the entry method of a console program?
- A Start
- B Run
- C Main
- D Init
Complete the code so the program prints Hello, C#!
class Program
{
static void Main()
{
Console.▓▓▓("Hello, C#!");
}
}
Console.WriteLine(...) to print a full line.Variables & data types
Value types vs reference types, common types and safe conversions
C# types fall into two categories: value types (int, double, bool, char, struct, etc. — allocated on the stack, assignment copies) and reference types (string, class, arrays — references point to heap objects).
- Integers:
intlongshortbyte - Floating point:
float(F)doubledecimal(M, high precision, ideal for money) - Others:
boolcharstring varlets the compiler infer the type;constdeclares a constant
Type conversion: implicit (safe, lossless) → explicit cast → Convert/Parse → TryParse (no exception thrown, safest).
int age = 20;
double pi = 3.14159;
decimal price = 19.99m; // use decimal for money
bool isStudent = true;
char grade = 'A';
string name = "Gavin";
var city = "London"; // var infers string
const double Gravity = 9.8;
// type conversion
double d = 9.7;
int n = (int)d; // explicit cast, truncates -> 9
string s = "123";
int parsed = int.Parse(s); // 123
if (int.TryParse("abc", out int result))
Console.WriteLine(result);
else
Console.WriteLine("parse failed");
123
parse failed
decimal suffix is m, the float suffix is f. Always use decimal for money; floating point has precision errors. Q1Which high-precision type is suited for financial / money calculations?
- A float
- B double
- C decimal
- D int
Q2What happens when int.TryParse fails to convert?
- A Throws an exception
- B Returns false
- C Returns null
- D Crashes the program
Safely parse the string "42" into an int, and only print on success.
string s = "42";
if (int.▓▓▓(s, out int n))
Console.WriteLine(n);
int.TryParse(s, out int n) does not throw and returns a bool.Operators & expressions
Arithmetic, logical, null operators and string interpolation
- Arithmetic:
+ - * / %. Note integer division7/2 == 3; for decimals write7/2.0 - Logical:
&& || !, supports short-circuit evaluation - null-related:
??null-coalescing (left is null → take right);?.null-conditional (skip call if left is null) - Ternary:
condition ? true : false - String interpolation:
$"Hello, {name}!"
int a = 7, b = 2;
Console.WriteLine(a / b); // 3 (integer division)
Console.WriteLine(a % b); // 1
Console.WriteLine(a / 2.0); // 3.5
bool adult = a > 5 && b < 5; // short-circuit
string name = null;
string display = name ?? "anonymous"; // "anonymous"
int? len = name?.Length; // null, no exception
string city = "London";
Console.WriteLine($"Welcome, {city}!"); // string interpolation
int max = a > b ? a : b; // ternary
1
3.5
anonymous
Welcome, London!
Q1In <code>a && b</code>, when a is false, is b evaluated?
- A Evaluated
- B Not evaluated (short-circuit)
Q2What does <code>name ?? "anonymous"</code> mean?
- A Use "anonymous" when name is null
- B name equals "anonymous"
- C Throws an exception
- D String concatenation
When name is null, let display take the default value "anonymous".
string name = null;
string display = name ▓▓▓ "anonymous";
??.Control flow
Conditionals, switch expressions and loops
C# control flow is similar to most languages, with modern enhancements:
if / else if / elseconditional branches- switch expressions (C# 8+): map with
=>, supports relational patterns and the_discard - Loops:
whiledo-whileforforeach breakexits a loop;continueskips this iteration
int score = 85;
// switch expression + relational pattern
string grade = score switch
{
>= 90 => "A",
>= 80 => "B",
>= 60 => "C",
_ => "D"
};
Console.WriteLine($"Grade: {grade}");
// for sum 1..100
int sum = 0;
for (int i = 1; i <= 100; i++)
sum += i;
Console.WriteLine($"sum = {sum}"); // 5050
// foreach over a string
foreach (var ch in "C#")
Console.Write(ch + " ");
sum = 5050
C #
Q1Which loop is most convenient for iterating an array/collection?
- A for
- B while
- C foreach
- D do-while
Q2What does <code>_</code> mean in a switch expression?
- A Multiplication
- B Default / wildcard
- C Pointer
- D Whitespace
Complete the for loop so i increments by 1 each iteration, summing 1 to 100.
int sum = 0;
for (int i = 1; i <= 100; ▓▓▓)
sum += i;
i++ or i += 1.Methods
Parameter passing, ref/out, overloading and recursion
- A method = a reusable block of code with a signature (name + parameter list) and a return type
- Pass by value (default): copies the argument; ref: passes a reference, can modify the original variable; out: output parameter, must be assigned inside the method
paramsvariadic parameter; method overloading: same name, different parameter list- Recursion: a method calling itself; must have a termination condition
// recursive factorial
static long Factorial(int n)
{
if (n <= 1) return 1;
return n * Factorial(n - 1);
}
// out returns multiple values
static void Divide(int a, int b, out int quotient, out int remainder)
{
quotient = a / b;
remainder = a % b;
}
// ref modifies the argument
static void Increment(ref int x) => x++;
// params variadic
static int Sum(params int[] nums)
{
int total = 0;
foreach (var n in nums) total += n;
return total;
}
Console.WriteLine(Factorial(5)); // 120
Divide(17, 5, out int q, out int r);
Console.WriteLine($"{q} ... {r}"); // 3 ... 2
int v = 10; Increment(ref v);
Console.WriteLine(v); // 11
Console.WriteLine(Sum(1, 2, 3, 4)); // 10
3 ... 2
11
10
Q1Which is true about ref and out?
- A Neither needs an initial value
- B out must be assigned inside the method
- C ref needs no initial value
- D They are exactly the same
Q2What is method overloading based on?
- A Return type
- B Parameter list
- C Different method names
- D Access modifiers
Complete the call: use out to receive the two results returned by Divide.
Divide(17, 5, ▓▓▓ int q, out int r);
out keyword.Arrays & strings
Array operations, string immutability and StringBuilder
- 1D arrays:
int[] a = {1,2,3};; utility methods likeArray.Sort/IndexOf/Reverse - Multidimensional:
int[,] mrectangular;int[][] jjagged array (array of arrays) - string is immutable: every concatenation creates a new object.
Length / Substring / IndexOf / Split / Replace / Contains / Trim - For high-frequency concatenation use
StringBuilderto avoid many temporary strings
int[] nums = { 3, 1, 4, 1, 5, 9, 2, 6 };
Array.Sort(nums);
Console.WriteLine(string.Join(", ", nums)); // 1, 1, 2, 3, 4, 5, 6, 9
// 2D array
int[,] matrix = { { 1, 2 }, { 3, 4 } };
// common string methods
string s = "Hello, World";
Console.WriteLine(s.Length); // 12
Console.WriteLine(s.Substring(0, 5)); // Hello
Console.WriteLine(s.IndexOf(',')); // 5
string[] parts = "a,b,c".Split(',');
Console.WriteLine(string.Join("|", parts)); // a|b|c
// StringBuilder for high-frequency concatenation
var sb = new System.Text.StringBuilder();
for (int i = 0; i < 3; i++)
sb.Append(i).Append(" ");
Console.WriteLine(sb.ToString()); // 0 1 2
12
Hello
5
a|b|c
0 1 2
Q1In C#, a string object is?
- A Mutable
- B Immutable
- C A value type
- D Has no length
Q2For large amounts of string concatenation, what should you prefer?
- A + concatenation
- B StringBuilder
- C char array
- D Fixed string
Split the string "a,b,c" into an array by comma.
string[] parts = "a,b,c".▓▓▓(',');
Split to break by a delimiter.Classes & objects
OOP basics: fields, properties, methods, constructors
A class is a blueprint (template); an object is an instance created with new. A class encapsulates data (fields/properties) and behavior (methods).
- Fields: private data storage; properties: controlled external access (get/set)
- Constructor: same name as the class, initializes the object
- Access modifiers:
publicpublic,privateprivate (default),protectedaccessible from subclasses,internalwithin the assembly - static: belongs to the class itself rather than an instance; shared by all instances
class Student
{
private int id; // field
public string Name { get; set; } // auto-property
public int Id // full property (with validation)
{
get => id;
set => id = value > 0 ? value : 0;
}
public Student(int id, string name) // constructor
{
Id = id;
Name = name;
}
public void Introduce() => Console.WriteLine($"I am {Name}, ID {Id}");
public static int Count = 0; // static member
}
var s = new Student(1, "Alice");
s.Introduce(); // I am Alice, ID 1
Student.Count++;
Q1Which is true about classes and objects?
- A A class is an instance of an object
- B An object is an instance of a class
- C They are exactly the same
- D A class cannot be instantiated
Q2A static member belongs to?
- A A specific instance
- B The class itself (shared by all instances)
- C A namespace
- D A specific method
Use the keyword to create a Student instance.
Student s = ▓▓▓ Student(1, "Alice");
new keyword to create an object instance.Properties, encapsulation & advanced constructors
Auto-properties, init, primary constructors and encapsulation
- Auto-property:
public string Name { get; set; }; the compiler generates a private backing field automatically - Read-only property:
{ get; }can only be assigned in the constructor - init setter (C# 9+): writable only during object initialization, immutable afterwards — flexible yet safe
- Full property: custom get/set logic (e.g. validation), with a private backing field
- Primary constructor (C# 12): parameters written directly after the class name, visible throughout the class
class Account
{
public string Owner { get; set; } // auto-property
public string Number { get; } // read-only (set in constructor)
public decimal Balance { get; init; } // init: writable only at init
public Account(string owner, string number)
{
Owner = owner;
Number = number;
}
private decimal rate; // full property + validation
public decimal Rate
{
get => rate;
set => rate = value is >= 0 and <= 1 ? value
: throw new ArgumentException("Invalid rate");
}
}
// C# 12 primary constructor
class Point(double x, double y)
{
public double X => x;
public double Y => y;
public double Distance() => Math.Sqrt(x * x + y * y);
}
// object initializer
var acc = new Account("Alice", "A001") { Balance = 100m };
Q1What does the init setter do?
- A Writable at any time
- B Writable only during object initialization
- C Read-only, never writable
- D Private, invisible
Q2What does the auto-property <code>public int X { get; set; }</code> do?
- A Throws an error
- B Compiler generates a private field
- C Has no field
- D Only has get
Make the Balance property assignable only at initialization (read-only afterwards).
public decimal Balance { get; ▓▓▓; }
init to make a property writable only once during initialization.Inheritance & polymorphism
base, virtual/override, is/as
- Inheritance:
class Dog : Animal, reuses base class members; C# is single-inheritance - virtual / override: base class marked virtual, subclass overrides with override — implements polymorphism
- Polymorphism: a parent reference pointing to a subclass object calls the subclass version of the method
basecalls the base constructor/method;sealedforbids further inheritance / overridingischecks a type and declares a variable;assafely converts (returns null on failure)
class Animal
{
public string Name { get; set; }
public Animal(string name) => Name = name;
public virtual void Speak() => Console.WriteLine("...");
}
class Dog : Animal
{
public Dog(string name) : base(name) { }
public override void Speak() => Console.WriteLine($"{Name}: Woof!");
}
class Cat : Animal
{
public Cat(string name) : base(name) { }
public override void Speak() => Console.WriteLine($"{Name}: Meow~");
}
// polymorphism: parent reference pointing to subclass objects
Animal[] zoo = { new Dog("Rex"), new Cat("Mimi"), new Animal("Unknown") };
foreach (var a in zoo) a.Speak();
// is pattern matching declares a variable / as safely converts
object o = new Dog("Blackie");
if (o is Dog d) d.Speak();
Animal x = o as Animal;
Mimi: Meow~
...
Blackie: Woof!
Q1For a subclass to override a parent method, the parent method must be marked?
- A sealed
- B virtual (subclass uses override)
- C static
- D private
Q2What does sealed on a class do?
- A Cannot be inherited
- B Cannot be instantiated
- C Is abstract
- D Is public
Override the parent's Speak method in the subclass.
class Dog : Animal
{
public ▓▓▓ void Speak() => Console.WriteLine("Woof!");
}
override to override a virtual method.Abstract classes & interfaces
abstract vs interface, when to use which
- Abstract class (abstract): cannot be instantiated; may contain fields, constructors, normal methods, abstract methods; single inheritance
- Interface (interface): a pure contract defining method signatures; a class can implement multiple interfaces; C# 8+ supports default implementations
- Choice: shared implementation/fields → abstract class; a cross-type capability contract → interface
- Interfaces are often named with an
Iprefix, e.g.IComparableIEnumerable
interface IShape
{
double Area();
void Print() => Console.WriteLine($"Area = {Area():F2}"); // default method
}
abstract class Shape
{
public abstract double Area(); // abstract method, subclass must implement
}
class Circle : Shape, IShape
{
public double Radius { get; set; }
public Circle(double r) => Radius = r;
public override double Area() => Math.PI * Radius * Radius;
}
class Rect : Shape, IShape
{
public double W { get; set; }
public double H { get; set; }
public override double Area() => W * H;
}
Shape s1 = new Circle(2);
IShape s2 = new Rect { W = 3, H = 4 };
Console.WriteLine(s1.Area()); // 12.566...
s2.Print(); // Area = 12.00
Area = 12.00
Q1How many interfaces can a class implement?
- A Only 1
- B Any number
- C 2
- D 0
Q2Can an abstract class be instantiated directly with new?
- A Yes
- B No
Make Circle both inherit Shape and implement the IShape interface.
class Circle : Shape, ▓▓▓
{
public override double Area() => ...;
}
Exception handling
try/catch/finally and custom exceptions
trywraps code that may fail;catchcatches a specific exception;finallyruns whether or not an exception occurred (resource cleanup)- Exceptions are classes inheriting from
Exception; common ones:NullReferenceExceptionIndexOutOfRangeExceptionFormatExceptionDivideByZeroException throwthrows;catch (...) when (condition)is an exception filter- Custom exceptions inherit from
Exceptionand are named ending with Exception
try
{
int[] arr = { 1, 2, 3 };
Console.WriteLine(arr[5]); // out of range
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("Out of range: " + ex.Message);
}
catch (DivideByZeroException)
{
Console.WriteLine("Cannot divide by zero");
}
catch (Exception ex) when (ex is FormatException)
{
Console.WriteLine("Invalid input format");
}
finally
{
Console.WriteLine("Cleanup done");
}
// custom exception
class InvalidScoreException : Exception
{
public InvalidScoreException(string msg) : base(msg) { }
}
static void CheckScore(int s)
{
if (s < 0 || s > 100)
throw new InvalidScoreException($"Invalid score: {s}");
}
Q1When does the finally block run?
- A Only on exceptions
- B Only on success
- C Whether or not an exception occurs
- D Never
Q2A custom exception usually inherits from?
- A Exception (or a subclass)
- B Object
- C Array
- D string
Complete the code to catch the exception thrown in the try block.
try
{
throw new Exception("Error occurred");
}
▓▓▓ (Exception ex)
{
Console.WriteLine(ex.Message);
}
catch keyword to catch an exception.Generics & collections
List, Dictionary, generic methods and constraints
Generics let you write one piece of code that works for many types, type-safely and without boxing. Common collections live in System.Collections.Generic:
List<T>: variable-length list,Add/Remove/Contains/CountDictionary<TKey, TValue>: key-value pairs, keys are unique,TryGetValueHashSet<T>: deduplicating set- Generic constraints:
where T : IComparable<T>requires T to be comparable
using System.Collections.Generic;
// generic List<T>
var nums = new List<int> { 3, 1, 4, 1, 5 };
nums.Add(9);
nums.Remove(1); // remove the first 1
Console.WriteLine(nums.Count); // 5
Console.WriteLine(nums.Contains(4)); // True
// generic Dictionary
var dict = new Dictionary<string, int>();
dict["apple"] = 3;
dict["banana"] = 5;
if (dict.TryGetValue("apple", out int cnt))
Console.WriteLine(cnt); // 3
// generic method + constraint
static T Max<T>(T a, T b) where T : IComparable<T>
=> a.CompareTo(b) >= 0 ? a : b;
Console.WriteLine(Max(3, 7)); // 7
Console.WriteLine(Max("cat", "dog")); // dog
True
3
7
dog
Q1What is the main benefit of generics?
- A Lower performance
- B Type safety + no boxing
- C Can only store int
- D Not reusable
Q2What is the requirement for keys in Dictionary<K,V>?
- A Must be int
- B Must be unique
- C Can be duplicated
- D Must be string
Add a constraint to the generic method Max: T must implement IComparable<T>.
static T Max<T>(T a, T b) ▓▓▓ T : IComparable<T>
=> a.CompareTo(b) >= 0 ? a : b;
where keyword.LINQ basics
Query expressions, method chains and deferred execution
LINQ (Language Integrated Query) lets you query any enumerable data source with a unified syntax — a killer feature of C#.
- Two styles: method syntax (chained calls, more common) and query syntax (SQL-like)
- Common:
Wherefilter,Selectproject,OrderBysort,GroupBygroup,First/Any/Sum/Averageaggregate - Deferred execution: Where/Select/OrderBy etc. don't compute until enumerated;
ToList()runs immediately - Heavy use of lambdas:
s => s.Score >= 80
using System;
using System.Collections.Generic;
using System.Linq;
record Student(int Id, string Name, int Score);
var students = new List<Student>
{
new(1, "Alice", 88),
new(2, "Bob", 72),
new(3, "Carol", 95),
new(4, "Dave", 60),
};
// method syntax
var top = students
.Where(s => s.Score >= 80)
.OrderByDescending(s => s.Score)
.Select(s => new { s.Name, s.Score });
foreach (var s in top)
Console.WriteLine($"{s.Name}: {s.Score}");
// Carol: 95 Alice: 88
// query syntax (equivalent)
var q = from s in students
where s.Score >= 80
orderby s.Score descending
select new { s.Name, s.Score };
// aggregation
Console.WriteLine(students.Average(s => s.Score)); // 78.75
Console.WriteLine(students.Any(s => s.Score == 100)); // False
Alice: 88
78.75
False
Q1Most LINQ query operators are?
- A Executed immediately
- B Deferred (on enumeration)
- C Executed at compile time
- D Never executed
Q2What does Select do?
- A Filter
- B Project / transform each element
- C Sort
- D Group
Use LINQ to filter students with score ≥ 80.
var top = students.▓▓▓(s => s.Score >= 80);
Where for conditional filtering.Delegates, events & file I/O
Action/Func, the event mechanism and file read/write (capstone)
- Delegate (delegate): a typed "pointer to a method".
Action<T>has no return value;Func<T,TResult>has a return value. Both are extremely common with lambdas. - Event (event): a publish-subscribe mechanism built on delegates. Outside the class you can only
+=/-=subscribe; you cannot directly trigger it. - File I/O:
System.IOprovidesFile/StreamReader/StreamWriterfor text reading and writing
using System;
using System.IO;
// delegate, Action, Func
Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 4)); // 7
Action<string> log = msg => Console.WriteLine($"[LOG] {msg}");
log("Startup");
// event: publish-subscribe
class Heater
{
public event EventHandler Boiled;
public void Boil()
{
Console.WriteLine("Heating...");
Boiled?.Invoke(this, EventArgs.Empty);
}
}
class Alarm
{
public void Ring(object sender, EventArgs e)
=> Console.WriteLine("Beep! Water boiled");
}
var h = new Heater();
var a = new Alarm();
h.Boiled += a.Ring; // subscribe
h.Boil();
// file I/O
File.WriteAllText("note.txt", "Hello C#");
string text = File.ReadAllText("note.txt");
Console.WriteLine(text);
[LOG] Startup
Heating...
Beep! Water boiled
Hello C#
Q1What is the difference between Action and Func?
- A No difference
- B Func has a return value, Action does not
- C Action has a return value
- D Both take no parameters
Q2What is the restriction of an event compared to a plain delegate?
- A No difference
- B Outside the class you can only += / -= subscribe, not call directly
- C Cannot subscribe
- D Read-only
Subscribe the alarm a.Ring to the water heater h.Boiled event.
h.Boiled ▓▓▓ a.Ring;
+= operator.🎓 Graduation quiz
Test everything from the 14 days — 6 questions in total
Great job making it here! Complete the 6 mixed questions below to verify your C# quick-start results. Get them all right to earn the graduation certificate.
G1What is the C# program execution flow?
- A Source → machine code → run
- B Source → IL → JIT → machine code
- C Source → interpreted
- D Source → bytecode → interpreted
G2Which statement about ref / out is correct?
- A Both need an initial value
- B out must be assigned inside the method
- C ref cannot modify the original variable
- D out is for input
G3What is the best way to concatenate strings thousands of times in a loop?
- A Use + directly
- B Use StringBuilder
- C Use char[]
- D new string every time
G4What is needed to implement runtime polymorphism?
- A Subclass uses new to hide a method
- B Parent virtual + subclass override
- C Both static
- D Use sealed
G5Which statement about interfaces is correct?
- A A class can implement only one interface
- B A class can implement multiple interfaces
- C Interfaces can contain fields
- D Interfaces can be instantiated
G6When does <code>students.Where(s => s.Score>80)</code> actually filter?
- A Immediately when Where is called
- B When the result is enumerated
- C At compile time
- D Never