C# and .NET Fundamentals
C# (pronounced "C sharp") is a modern, general-purpose programming language designed for type safety, productivity, maintainability and high performance.
Concept
C# (pronounced "C sharp") is a modern, general-purpose programming language designed for type safety, productivity, maintainability and high performance. It is statically typed (types are checked by the compiler), object-oriented (programs are built from classes and objects) and multi-paradigm (it also supports functional, generic, asynchronous and data-oriented styles). Its syntax belongs to the C family (braces, semicolons), so C, C++, Java and JavaScript developers feel at home quickly..NET is the platform that builds and runs C# programs. Its parts:
Everything needed to develop: compilers, the dotnet CLI, MSBuild, templates
Everything needed to run apps: the CLR plus the base libraries
The command-line driver: dotnet new, build, run, test, publish Base Class Library (BCL)
Thousands of ready-made types: collections, I/O, networking, JSON, threading Common Language Runtime (CLR)
The virtual machine: JIT compiler, garbage collector, type loader, exception handling, security checks C# compiler (Roslyn)
Turns .cs files into IL inside an assembly The package manager and public package gallery (nuget.org)
The compiled output files (.dll / .exe) containing IL and metadata
The small native host (dotnet.exe or an apphost .exe) that starts the runtime
C# is one of several .NET languages (F# and Visual Basic are others); they all compile to the same IL and share the BCL.
Each C# version added major features that later modules teach in depth:
Version (year) Classes, interfaces, structs, properties, delegates, events
Generics, nullable value types, iterators (yield), anonymous methods
LINQ, lambda expressions, var, extension methods, object initializers async / await
String interpolation, nameof, ?., expression-bodied members
Tuples, deconstruction, pattern matching, Span<T>, ref locals
Nullable reference types, async streams, switch expressions, default interface members
Records, init setters, top-level statements, relational/logical patterns
Global using, file-scoped namespaces, record structs Raw string literals, list patterns, required members, generic math
Primary constructors for all classes, collection expressions [1, 2, 3]
params collections, new lock type, \e escape C# 14 (2025,.NET 10)
Extension members, field keyword in properties, null-conditional assignment C# Program Execution
Compilation: the C# compiler checks types and produces Intermediate Language (IL), a CPU-independent instruction set, plus metadata describing every type and member.
The IL and metadata are packaged in an assembly (.dll).
At run time the CLR loads the assembly and the JIT (just-in-time) compiler translates each method's IL to native code the first time it is called (tiered compilation later re-optimizes hot methods).
While the program runs, the garbage collector (GC) automatically frees memory for objects that are no longer reachable.
Ahead-of-time options also exist: ReadyToRun (pre-compiled code in the assembly) and Native AOT (a single native executable with no JIT).
flowchart TD
A[C# source code .cs] --> B[C# compiler Roslyn]
B --> C[IL + metadata in an assembly .dll]
C --> D[.NET runtime CLR]
D --> E[JIT compiler]
E --> F[Native machine code]
F --> G[CPU]Why It Matters
Knowing the pipeline explains many practical things: why the same .dll runs on Windows, Linux and macOS; why the first call to a method is slower (JIT); why memory is managed for you; why reflection can inspect any type (metadata); and what interviewers mean by "IL", "CLR" and "JIT".
Syntax
dotnet --info # SDKs, runtimes and environment
dotnet --version # SDK version in use
dotnet --list-sdks
dotnet --list-runtimesExample
This program asks the runtime about itself and shows the actual IL bytes the compiler produced for a method.
GetILAsByteArray() returns the method's IL: 02 = ldarg.0 (push first argument), 03 = ldarg.1 (push second), 58 = add, 2A = ret. The JIT turns these four bytes into native CPU instructions when Add is first called.
using System.Reflection;
using System.Runtime;
using System.Runtime.InteropServices;
// Where is this C# code actually running?
Console.WriteLine($"Runtime : {RuntimeInformation.FrameworkDescription}");
Console.WriteLine($"C# int is : {typeof(int).FullName} (from {typeof(int).Assembly.GetName().Name})");
Console.WriteLine($"64-bit process: {Environment.Is64BitProcess}");
Console.WriteLine($"GC generations: 0..{GC.MaxGeneration}, server GC: {GCSettings.IsServerGC}");
// Every method is compiled to IL (Intermediate Language) stored in the assembly.
MethodInfo add = typeof(Calculator).GetMethod(nameof(Calculator.Add))!;
byte[] il = add.GetMethodBody()!.GetILAsByteArray()!;
Console.WriteLine($"Calculator.Add is {il.Length} bytes of IL: {BitConverter.ToString(il)}");
Console.WriteLine($"Add(2, 3) after JIT compilation = {Calculator.Add(2, 3)}");
static class Calculator
{
public static int Add(int a, int b) => a + b;
}Expected Result
(Your runtime version may be newer. Calculator.Add compiles to the same 4 IL bytes everywhere, because IL is CPU-independent.)
Runtime : .NET 10.0.12
C# int is : System.Int32 (from System.Private.CoreLib)
64-bit process: True
GC generations: 0..2, server GC: False
Calculator.Add is 4 bytes of IL: 02-03-58-2A
Add(2, 3) after JIT compilation = 5Common Mistakes
Confusing the SDK (for building) with the runtime (for running): a machine that only runs apps needs just the runtime.
Thinking C# is interpreted: IL is always compiled to native code (by the JIT or ahead of time).
Thinking C# only runs on Windows: modern .NET is cross-platform.
Mixing up ".NET Framework" (the older Windows-only version, 4.8 is the last) with modern ".NET" (5, 6, 7, 8, 9, 10, …).
Best Practices
Target a currently supported .NET version (LTS releases such as .NET 8 and .NET 10 are supported for three years).
Use dotnet --info when diagnosing "works on my machine" problems.
Keep the language version at the default for your target framework unless you have a reason to change it.
Interview Relevance
High for entry-level roles: "What is the CLR?", "What is IL?", "What does the JIT do?", "Difference between .NET Framework and .NET?", "What is an assembly?", "What is managed code?".
Practice Questions
Name four components of .NET and say what each does.
What is stored in an assembly besides IL?
Why is the first call to a method slightly slower than later calls?
Which C# version introduced async/await? Which introduced records?
Modify the example to print the IL of a method that multiplies two numbers. Which byte replaces 58?
Quick Quiz
Q1. (Multiple choice) What does the C# compiler produce? A) Native machine code B) Intermediate Language (IL) C) JavaScript D) Java bytecode
Answer: B. Roslyn emits IL and metadata into an assembly; the JIT or an AOT compiler produces native code later.
Q2. (True/False) The garbage collector must be called manually to free objects.
Answer: False. The GC runs automatically; calling GC.Collect() is rarely appropriate.
Q3. (Predict the output) What does the example print for Add(2, 3) after JIT compilation?
Answer: 5 — the IL ldarg.0, ldarg.1, add, ret adds the two arguments.
Q4. (Multiple choice) Which component manages memory at run time? A) NuGet B) MSBuild C) The CLR's garbage collector D) The C# compiler Answer: C.
Coding Challenge
Write a program that prints the .NET runtime description, whether the process is 64-bit, and the number of processors (Environment.ProcessorCount).
using System.Runtime.InteropServices;
Console.WriteLine(RuntimeInformation.FrameworkDescription);
Console.WriteLine(Environment.Is64BitProcess);
Console.WriteLine(Environment.ProcessorCount);