
C# Programming Made Eazy
1. Introduction to C# and .NET (C# 12 / .NET 8)
What is C#?
C# is a modern, multi-paradigm programming language developed by Microsoft. It is widely used for building web apps, APIs, desktop software, mobile apps (via Xamarin or MAUI), cloud-based services, and games (using Unity). With each version, C# evolves to offer more concise, expressive, and performant code. C# 12 introduces features like primary constructors for non-record classes and default lambda parameters.
Overview of the .NET Ecosystem (.NET 8)
.NET 8 is the latest long-term support (LTS) release of the .NET platform. It’s a unified, cross-platform runtime and development framework that allows you to build apps for Windows, Linux, macOS, iOS, Android, and the web.
- Cross-Platform: Run C# code on any OS.
- Unified Platform: Web, desktop, mobile, cloud, and IoT development in one ecosystem.
- Performance: Major runtime and JIT improvements make .NET 8 faster than previous versions.
- Language Innovation: Latest C# features like raw string literals, primary constructors, and improved pattern matching.
Installing Visual Studio / VS Code + .NET 8 SDK
To begin C# development with .NET 8:
- Visual Studio 2022+ (17.8 or later): Fully supports .NET 8 and C# 12.
- Visual Studio Code: Lightweight and cross-platform with C# Dev Kit and .NET SDK.
- .NET SDK 8: Required to build and run modern C# applications.
Download from dotnet.microsoft.com.
First Console App: Hello World (Top-Level Statements)
Starting with C# 9 and refined in C# 12, you can write your first app using top-level statements—no need for boilerplate class or Main
method:
Console.WriteLine("Hello, World!");
This is a valid and complete C# program in .NET 8. To create and run it:
dotnet new console -n HelloWorldApp
cd HelloWorldApp
dotnet run
C# File Structure and Compilation Process
Modern C# supports file-scoped namespaces, top-level statements, and global usings to reduce clutter:
namespace HelloWorld;
Console.WriteLine("Hello from C# 12 and .NET 8!");
The compilation process:
- C# code is compiled to Intermediate Language (IL).
- IL is JIT-compiled and executed by the Common Language Runtime (CLR).
- The .NET runtime handles memory management, garbage collection, and type safety.
2. Basic Syntax and Data Types (C# 12)
Variables and Constants
Variables are used to store data values. In C#, you must declare a variable with its type. Constants are immutable values declared using the const
keyword.
// Variable declaration
int age = 30;
double price = 99.99;
// Constant declaration
const double Pi = 3.14159;
Data Types in C#
C# is a statically typed language, and variables must be declared with a type. Common built-in types include:
- int: Whole numbers (e.g., 1, 100)
- double: Decimal numbers (e.g., 3.14)
- char: A single character (e.g., 'A')
- string: A sequence of characters (e.g., "Hello")
- bool: Boolean values (true or false)
int score = 100;
double temperature = 36.6;
char grade = 'A';
string name = "Kumar";
bool isActive = true;
Type Conversion and Parsing
C# supports implicit and explicit type conversions. You can also convert strings to numeric types using parsing methods.
// Implicit conversion
int x = 10;
double y = x; // OK
// Explicit conversion
double a = 9.8;
int b = (int)a; // Requires cast
// Parsing from string
string input = "123";
int number = int.Parse(input);
Comments and Naming Conventions
Comments help explain code. C# supports single-line and multi-line comments.
// This is a single-line comment
/*
This is a multi-line comment
Spanning multiple lines
*/
Naming Conventions:
- Use
camelCase
for local variables and parameters - Use
PascalCase
for method names, class names, and properties - Avoid using abbreviations or single-letter variable names
Operators in C#
C# provides various operators for performing operations:
- Arithmetic:
+
,-
,*
,/
,%
- Comparison:
==
,!=
,>
,<
,>=
,<=
- Logical:
&&
(AND),||
(OR),!
(NOT)
// Arithmetic
int sum = 5 + 3;
int mod = 10 % 3;
// Comparison
bool isEqual = (5 == 5);
// Logical
bool result = (true && false) || true;
3. Control Flow (C# 12)
if, else if, else Statements
Conditional statements allow you to execute blocks of code based on conditions. C# uses if
, else if
, and else
to control flow.
int marks = 85;
if (marks >= 90)
Console.WriteLine("Grade A");
else if (marks >= 75)
Console.WriteLine("Grade B");
else
Console.WriteLine("Grade C");
switch Statement
The switch
statement is useful when comparing a variable against multiple values. In C# 8+, pattern matching in switch is supported. C# 12 supports even more powerful patterns.
int day = 3;
switch (day)
{
case 1:
Console.WriteLine("Monday");
break;
case 2:
Console.WriteLine("Tuesday");
break;
case 3:
Console.WriteLine("Wednesday");
break;
default:
Console.WriteLine("Invalid day");
break;
}
Loops: for, while, do-while
Loops allow you to repeat code multiple times. Common loop types include:
- for loop: When the number of iterations is known
- while loop: Repeats while a condition is true
- do-while loop: Executes at least once before checking the condition
// for loop
for (int i = 1; i <= 5; i++)
{
Console.WriteLine(i);
}
// while loop
int j = 1;
while (j <= 5)
{
Console.WriteLine(j);
j++;
}
// do-while loop
int k = 1;
do
{
Console.WriteLine(k);
k++;
} while (k <= 5);
break and continue
The break
statement exits the loop early, while continue
skips the current iteration and moves to the next.
for (int i = 1; i <= 5; i++)
{
if (i == 3)
continue; // skip when i is 3
if (i == 5)
break; // exit loop when i is 5
Console.WriteLine(i);
}
Nested Loops and Pattern Printing
Nested loops are loops inside other loops. These are useful for tasks like printing patterns or processing multidimensional arrays.
// Pattern: right-angle triangle
int rows = 5;
for (int i = 1; i <= rows; i++)
{
for (int j = 1; j <= i; j++)
{
Console.Write("* ");
}
Console.WriteLine();
}
4. Methods & Parameters (C# 12)
Defining and Calling Methods
A method is a block of code that performs a specific task. It improves code reusability and readability. You define a method using a return type, a name, and parameters (if any).
// Method definition
void Greet()
{
Console.WriteLine("Hello, welcome to C#!");
}
// Calling the method
Greet();
Parameters and Return Types
Methods can accept input parameters and return values using the return
keyword.
// Method with parameters and return value
int Add(int a, int b)
{
return a + b;
}
// Usage
int result = Add(5, 3);
Console.WriteLine($"Sum = {result}");
Method Overloading
Method overloading allows multiple methods with the same name but different parameters. The compiler chooses the appropriate method based on the arguments.
void Show()
{
Console.WriteLine("No parameters");
}
void Show(string name)
{
Console.WriteLine($"Hello, {name}");
}
Show(); // No parameters
Show("Kumar"); // Hello, Kumar
ref
, out
, and params
Keywords
ref: Passes a variable by reference. The original value is modified.
void Increment(ref int num)
{
num++;
}
int x = 5;
Increment(ref x);
Console.WriteLine(x); // 6
out: Passes a variable by reference, but it doesn’t need to be initialized before calling.
void GetValues(out int a, out int b)
{
a = 10;
b = 20;
}
int val1, val2;
GetValues(out val1, out val2);
params: Allows passing a variable number of arguments as an array.
int Sum(params int[] numbers)
{
int total = 0;
foreach (var num in numbers)
total += num;
return total;
}
int totalSum = Sum(1, 2, 3, 4); // 10
Recursion
Recursion is when a method calls itself to solve a smaller instance of a problem. A common example is calculating factorial:
int Factorial(int n)
{
if (n == 0)
return 1;
return n * Factorial(n - 1);
}
int fact = Factorial(5); // 120
5. Object-Oriented Programming (C# 12)
Classes and Objects
A class is a blueprint for creating objects. An object is an instance of a class containing real values.
// Class definition
class Person
{
public string Name;
public void SayHello()
{
Console.WriteLine($"Hello, I am {Name}");
}
}
// Creating and using an object
Person p = new Person();
p.Name = "Kumar";
p.SayHello();
Fields, Properties, and Methods
- Fields are variables declared inside a class.
- Properties provide controlled access to fields.
- Methods define behavior.
class Product
{
private int _price;
public int Price
{
get { return _price; }
set { _price = value; }
}
public void Display()
{
Console.WriteLine($"Price: {Price}");
}
}
Constructors and Destructors
A constructor is a special method invoked when an object is created. A destructor (~ClassName) is called by the garbage collector to free resources (rarely used in .NET).
class Car
{
public string Model;
// Constructor
public Car(string model)
{
Model = model;
}
// Destructor
~Car()
{
Console.WriteLine("Destructor called");
}
}
Access Modifiers (public, private, protected)
- public: Accessible from anywhere.
- private: Accessible only within the class.
- protected: Accessible within the class and derived classes.
class Example
{
private int secret = 42;
public int visible = 100;
}
Inheritance and the base
Keyword
Inheritance allows a class to acquire the members of another class. The base
keyword is used to call the base class constructor or method.
class Animal
{
public void Speak() => Console.WriteLine("Animal speaks");
}
class Dog : Animal
{
public void Bark() => Console.WriteLine("Dog barks");
}
Dog d = new Dog();
d.Speak();
d.Bark();
Method Overriding and Polymorphism
Method overriding lets a subclass provide a specific implementation of a method declared in the base class. The virtual
and override
keywords enable this.
class Animal
{
public virtual void Speak() => Console.WriteLine("Animal speaks");
}
class Cat : Animal
{
public override void Speak() => Console.WriteLine("Cat meows");
}
Animal a = new Cat();
a.Speak(); // Cat meows (runtime polymorphism)
Interfaces and Abstract Classes
- An interface defines a contract with only method/property signatures.
- An abstract class can have both abstract and concrete methods.
// Interface
interface ILogger
{
void Log(string message);
}
// Abstract class
abstract class Shape
{
public abstract double Area();
public void Describe() => Console.WriteLine("Shape description");
}
// Implementation
class Rectangle : Shape
{
public int Width = 5;
public int Height = 10;
public override double Area() => Width * Height;
}
6. Collections and Arrays (C# 12)
Arrays in C#
Arrays are fixed-size collections that store elements of the same type. C# supports 1D, 2D (multi-dimensional), and jagged (array of arrays) arrays.
1D Array
int[] numbers = { 1, 2, 3, 4, 5 };
Console.WriteLine(numbers[2]); // Output: 3
2D Array
int[,] matrix = {
{ 1, 2 },
{ 3, 4 }
};
Console.WriteLine(matrix[1, 1]); // Output: 4
Jagged Array
int[][] jagged = new int[2][];
jagged[0] = new int[] { 1, 2 };
jagged[1] = new int[] { 3, 4, 5 };
Console.WriteLine(jagged[1][2]); // Output: 5
Common Collections
The System.Collections.Generic
namespace provides flexible and type-safe collection classes.
List<T>
A dynamic array that grows/shrinks as needed.
List<string> fruits = new() { "Apple", "Banana" };
fruits.Add("Cherry");
Console.WriteLine(fruits[1]); // Banana
Dictionary<TKey, TValue>
Stores key-value pairs for fast lookups.
Dictionary<string, int> ages = new()
{
["Alice"] = 25,
["Bob"] = 30
};
Console.WriteLine(ages["Bob"]); // 30
HashSet<T>
Stores unique values only, no duplicates.
HashSet<int> uniqueNumbers = new() { 1, 2, 2, 3 };
Console.WriteLine(uniqueNumbers.Count); // 3
foreach
Loop
The foreach
loop iterates over arrays or collections without needing index tracking.
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
Sorting and Searching Collections
Sorting a List
List<int> numbers = new() { 5, 2, 8, 1 };
numbers.Sort();
Console.WriteLine(string.Join(", ", numbers)); // 1, 2, 5, 8
Searching in a List
bool hasEight = numbers.Contains(8); // true
int index = numbers.IndexOf(5); // 2
Sorting Dictionary by Key
var sorted = ages.OrderBy(kv => kv.Key);
foreach (var kv in sorted)
Console.WriteLine($"{kv.Key}: {kv.Value}");
7. Exception Handling (C# 12)
try, catch, finally
In C#, exceptions are handled using try
, catch
, and finally
blocks.
- try
contains the code that might throw an exception.
- catch
handles the exception.
- finally
executes regardless of whether an exception occurs.
try
{
int x = 10;
int y = 0;
int result = x / y;
}
catch (DivideByZeroException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
Console.WriteLine("Cleanup or final steps.");
}
Common Exception Types
System.Exception
: Base class for all exceptionsDivideByZeroException
: Thrown when dividing by zeroNullReferenceException
: Object reference not setIndexOutOfRangeException
: Accessing an invalid indexInvalidOperationException
: Operation not valid for the object stateFileNotFoundException
: File not found during file operations
Throwing Exceptions
You can throw exceptions using the throw
keyword:
int age = -1;
if (age < 0)
throw new ArgumentException("Age cannot be negative.");
Creating Custom Exceptions
You can define your own exception types by inheriting from Exception
:
class CustomException : Exception
{
public CustomException(string message) : base(message) { }
}
// Usage
throw new CustomException("Something went wrong in your logic.");
8. File I/O Basics (C# 12)
Reading and Writing Text Files
The System.IO
namespace provides classes for file and directory operations. Common tasks include reading from and writing to text files.
Write Text to a File
string filePath = "example.txt";
File.WriteAllText(filePath, "Hello, this is a sample text.");
Read Text from a File
string content = File.ReadAllText("example.txt");
Console.WriteLine(content);
Read All Lines
string[] lines = File.ReadAllLines("example.txt");
foreach (var line in lines)
Console.WriteLine(line);
Checking File Existence
Before performing operations, it’s good to check if the file exists:
if (File.Exists("example.txt"))
{
Console.WriteLine("File exists.");
}
Working with Directories
The Directory
class allows creating, deleting, and checking folders:
// Create a new directory
string folderPath = "MyFolder";
Directory.CreateDirectory(folderPath);
// List files in a directory
string[] files = Directory.GetFiles(folderPath);
foreach (var file in files)
Console.WriteLine(file);
// Check if a directory exists
if (Directory.Exists(folderPath))
{
Console.WriteLine("Directory found.");
}
9. Introduction to LINQ (C# 12)
What is LINQ?
LINQ (Language Integrated Query) is a powerful feature in C# that allows you to write queries directly within your C# code to retrieve and manipulate data from collections, databases, XML, and more. It brings SQL-like query capabilities into the C# language itself.
Basic LINQ Queries
int[] numbers = { 1, 2, 3, 4, 5, 6 };
// LINQ query syntax
var evenNumbers = from num in numbers
where num % 2 == 0
select num;
foreach (var n in evenNumbers)
Console.WriteLine(n);
Filtering, Projection, Aggregation
Filtering
var highScores = numbers.Where(n => n > 3);
foreach (var score in highScores)
Console.WriteLine(score);
Projection (Select)
var squares = numbers.Select(n => n * n);
foreach (var sq in squares)
Console.WriteLine(sq);
Aggregation
int sum = numbers.Sum();
int count = numbers.Count();
int max = numbers.Max();
int min = numbers.Min();
LINQ with Lists and Arrays
LINQ works with any collection that implements IEnumerable<T>
, including arrays and generic lists.
List<string> names = new() { "Alice", "Bob", "Charlie" };
var shortNames = names.Where(name => name.Length <= 4);
foreach (var name in shortNames)
Console.WriteLine(name);
LINQ makes data processing more readable and expressive, reducing the need for complex loops and conditionals.