C# Fundamentals
C# (pronounced "C Sharp") is a modern, type-safe, object-oriented programming language developed by Microsoft. It runs on the .NET platform and is widely used for building enterprise applications, web services, desktop applications, and cloud-native systems. Understanding C# fundamentals is essential for developers working in the Microsoft ecosystem and platform engineering.
What is C#
C# is a statically-typed, compiled language that combines the power of C++ with the simplicity of Visual Basic. It was designed to be simple, modern, and general-purpose, making it suitable for a wide range of development scenarios.
Key characteristics:
- Type-safe: Prevents type errors at compile time
- Object-oriented: Supports classes, inheritance, interfaces, and polymorphism
- Cross-platform: Runs on Windows, Linux, and macOS via .NET
- Memory-managed: Automatic garbage collection handles memory
- Component-oriented: Designed for building reusable components
graph TB
A[C# Source Code] --> B[C# Compiler]
B --> C[Intermediate Language - IL]
C --> D[CLR - Common Language Runtime]
D --> E[JIT Compilation]
E --> F[Native Machine Code]
F --> G[Execution]
Basic Syntax and Data Types
C# provides a rich set of built-in data types divided into value types and reference types.
Value Types
Value types store data directly and are allocated on the stack.
// Integer types
int age = 30;
long population = 7800000000L;
short temperature = -15;
byte level = 255;
// Floating-point types
float rate = 3.14f;
double price = 19.99;
decimal money = 1234.56m; // Use for financial calculations
// Boolean
bool isActive = true;
// Character
char grade = 'A';
Reference Types
Reference types store a reference to the data and are allocated on the heap.
// String
string name = "Alice";
string message = $"Hello, {name}!"; // String interpolation
// Arrays
int[] numbers = { 1, 2, 3, 4, 5 };
string[] names = new string[3];
// Objects
object obj = new object();
Variables and Constants
// Variable declaration
int count = 0;
string text;
// Type inference with var
var number = 42; // Compiler infers int
var name = "Bob"; // Compiler infers string
// Constants
const double PI = 3.14159;
const string AppName = "MyApp";
// Read-only fields (runtime constant)
readonly DateTime startTime = DateTime.Now;
Control Flow
Conditional Statements
// If-else
int score = 85;
if (score >= 90)
{
Console.WriteLine("Grade: A");
}
else if (score >= 80)
{
Console.WriteLine("Grade: B");
}
else
{
Console.WriteLine("Grade: C");
}
// Ternary operator
string result = (score >= 60) ? "Pass" : "Fail";
// Switch statement (traditional)
string day = "Monday";
switch (day)
{
case "Monday":
Console.WriteLine("Start of week");
break;
case "Friday":
Console.WriteLine("End of week");
break;
default:
Console.WriteLine("Midweek");
break;
}
// Switch expression (C# 8.0+)
string dayType = day switch
{
"Monday" or "Tuesday" => "Start of week",
"Friday" => "End of week",
_ => "Midweek"
};
Loops
// For loop
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Count: {i}");
}
// While loop
int counter = 0;
while (counter < 5)
{
Console.WriteLine($"Counter: {counter}");
counter++;
}
// Do-while loop
int num = 0;
do
{
Console.WriteLine($"Number: {num}");
num++;
} while (num < 5);
// Foreach loop
string[] fruits = { "Apple", "Banana", "Orange" };
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
graph TD
A[Start Loop] --> B{Condition?}
B -->|True| C[Execute Block]
C --> D[Update]
D --> B
B -->|False| E[Exit Loop]
Methods
Methods are blocks of code that perform specific tasks and can be reused.
// Method with no return value
void PrintMessage(string message)
{
Console.WriteLine(message);
}
// Method with return value
int Add(int a, int b)
{
return a + b;
}
// Method with optional parameters
void Greet(string name, string greeting = "Hello")
{
Console.WriteLine($"{greeting}, {name}!");
}
// Method with named parameters
Greet(greeting: "Hi", name: "Alice");
// Expression-bodied method (C# 6.0+)
int Multiply(int x, int y) => x * y;
// Method overloading
int Calculate(int a, int b) => a + b;
double Calculate(double a, double b) => a + b;
string Calculate(string a, string b) => a + b;
Classes and Objects
Classes are blueprints for creating objects.
public class Person
{
// Fields (private by convention)
private string name;
private int age;
// Properties (public access)
public string Name
{
get { return name; }
set { name = value; }
}
// Auto-implemented property
public int Age { get; set; }
// Constructor
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
// Method
public void Introduce()
{
Console.WriteLine($"Hi, I'm {name} and I'm {age} years old.");
}
}
// Creating and using objects
Person person = new Person("Alice", 30);
person.Introduce();
Console.WriteLine($"Name: {person.Name}");
// Object initializer syntax
Person person2 = new Person("Bob", 25)
{
Age = 26
};
Namespaces
Namespaces organize code and prevent naming conflicts.
namespace MyApplication.Models
{
public class User
{
public string Username { get; set; }
}
}
namespace MyApplication.Services
{
using MyApplication.Models;
public class UserService
{
public User GetUser(string username)
{
return new User { Username = username };
}
}
}
// Using declarations
using System;
using System.Collections.Generic;
using MyApplication.Services;
Exception Handling
Exception handling manages runtime errors gracefully.
try
{
int result = Divide(10, 0);
}
catch (DivideByZeroException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error: {ex.Message}");
}
finally
{
Console.WriteLine("Cleanup code runs regardless");
}
// Throwing exceptions
int Divide(int a, int b)
{
if (b == 0)
{
throw new DivideByZeroException("Cannot divide by zero");
}
return a / b;
}
sequenceDiagram
participant Code
participant Try Block
participant Catch Block
participant Finally Block
Code->>Try Block: Execute code
alt Exception Occurs
Try Block->>Catch Block: Throw exception
Catch Block->>Catch Block: Handle exception
else No Exception
Try Block->>Try Block: Complete normally
end
Try Block->>Finally Block: Always execute
Finally Block->>Code: Return control
Collections
C# provides various collection types for storing groups of objects.
using System.Collections.Generic;
// List (dynamic array)
List<string> names = new List<string>();
names.Add("Alice");
names.Add("Bob");
names.Remove("Alice");
int count = names.Count;
// Dictionary (key-value pairs)
Dictionary<string, int> ages = new Dictionary<string, int>();
ages["Alice"] = 30;
ages["Bob"] = 25;
int aliceAge = ages["Alice"];
// HashSet (unique values)
HashSet<int> uniqueNumbers = new HashSet<int>();
uniqueNumbers.Add(1);
uniqueNumbers.Add(1); // Duplicate ignored
bool contains = uniqueNumbers.Contains(1);
// Queue (FIFO)
Queue<string> queue = new Queue<string>();
queue.Enqueue("First");
queue.Enqueue("Second");
string first = queue.Dequeue();
// Stack (LIFO)
Stack<int> stack = new Stack<int>();
stack.Push(1);
stack.Push(2);
int top = stack.Pop();
LINQ Basics
Language Integrated Query (LINQ) provides a consistent way to query collections.
using System.Linq;
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Query syntax
var evenNumbers = from n in numbers
where n % 2 == 0
select n;
// Method syntax
var evenNumbers2 = numbers.Where(n => n % 2 == 0);
// Common LINQ operations
var sum = numbers.Sum();
var average = numbers.Average();
var max = numbers.Max();
var first = numbers.First();
var filtered = numbers.Where(n => n > 5).ToList();
var sorted = numbers.OrderByDescending(n => n);
Practical Example: Simple Console Application
using System;
using System.Collections.Generic;
using System.Linq;
namespace TaskManager
{
public class Task
{
public int Id { get; set; }
public string Description { get; set; }
public bool IsCompleted { get; set; }
}
public class TaskManager
{
private List<Task> tasks = new List<Task>();
private int nextId = 1;
public void AddTask(string description)
{
tasks.Add(new Task
{
Id = nextId++,
Description = description,
IsCompleted = false
});
Console.WriteLine($"Task added: {description}");
}
public void CompleteTask(int id)
{
var task = tasks.FirstOrDefault(t => t.Id == id);
if (task != null)
{
task.IsCompleted = true;
Console.WriteLine($"Task completed: {task.Description}");
}
}
public void ListTasks()
{
Console.WriteLine("\nTasks:");
foreach (var task in tasks)
{
string status = task.IsCompleted ? "[X]" : "[ ]";
Console.WriteLine($"{task.Id}. {status} {task.Description}");
}
}
}
class Program
{
static void Main(string[] args)
{
var manager = new TaskManager();
manager.AddTask("Learn C# fundamentals");
manager.AddTask("Build a console app");
manager.ListTasks();
manager.CompleteTask(1);
manager.ListTasks();
}
}
}
Key Takeaways
- C# is a type-safe, object-oriented language running on the .NET platform
- Value types store data directly on the stack, while reference types store references on the heap
- Control flow includes if-else, switch, for, while, and foreach statements
- Methods encapsulate reusable code blocks with optional parameters and return values
- Classes are blueprints for objects with properties, methods, and constructors
- Namespaces organize code and prevent naming conflicts
- Exception handling uses try-catch-finally blocks to manage runtime errors
- Collections like List, Dictionary, and HashSet store groups of objects
- LINQ provides a consistent query syntax for working with collections
- Modern C# features like auto-properties, string interpolation, and switch expressions simplify code