Introduction to C# & .NET Setup
What is C#?
C# (pronounced "C-sharp") is a modern, object-oriented, and type-safe programming language developed by Microsoft. It is designed to be simple, powerful, and versatile. While it shares roots with C and C++, it incorporates modern features that make it more productive and less prone to errors.
C# is the primary language for the .NET ecosystem, meaning it can be used to build almost anything:
- Enterprise Software: Robust backend systems for banks and corporations.
- Web Development: Using ASP.NET Core to build high-performance APIs and websites.
- Game Development: The industry standard for the Unity Engine.
- Cloud Services: Deep integration with Microsoft Azure for scalable cloud apps.
- Mobile Apps: Cross-platform development via .NET MAUI.
The .NET Ecosystem: How it Works
To understand C#, you must understand .NET. C# is the language, but .NET is the runtime and library that executes the code.
C# does not compile directly into machine code (binary). Instead, it follows a two-step process:
- C# Source Code $\rightarrow$ Compiled into CIL (Common Intermediate Language).
- CIL $\rightarrow$ Translated by the CLR (Common Language Runtime) using JIT (Just-In-Time) Compilation into machine code that your specific CPU understands.
This is why C# is cross-platform; the CIL is the same regardless of whether you are on Windows, Linux, or macOS.
Setting Up Your Environment
To start developing, you need two main components: the SDK and an IDE.
1. The .NET SDK (Software Development Kit)
The SDK contains the compilers, libraries, and tools (like the dotnet command) needed to build applications. Download the latest version from dotnet.microsoft.com.
dotnet --version
# Expected Output: 8.0.x (or the latest stable version)
2. Choosing Your Editor (IDE)
- Visual Studio 2022: The "Full Power" IDE. Best for large enterprise projects and Windows desktop apps.
- VS Code: A lightweight, fast editor. Preferred by many professionals for web development and cross-platform work (requires the "C# Dev Kit" extension).
- JetBrains Rider: A premium, high-performance cross-platform IDE.
Anatomy of Your First Program
Let's look at a standard C# program and break down exactly what each line is doing.
using System; class Program { static void Main() { Console.WriteLine("Hello, World!"); Console.WriteLine("Welcome to C# Mastery!"); } }
Code Breakdown:
using System;: This tells the program to use the System namespace, which contains fundamental classes likeConsole.class Program: C# is an Object-Oriented language. Every piece of code must live inside a class.static void Main(): This is the Entry Point. When you run your app, the .NET runtime looks for this exact method to start execution.Console.WriteLine(): A method used to print text to the terminal/console.
💻 Try It Yourself - Multi-Language Compiler
Practice C# and many other programming languages right here in your browser! Switch between languages, modify the code, and click "Run" to see results instantly.
💡 Practice Tips:
- Switch to C# in the language selector and try the .NET examples
- Experiment with C#'s strong typing and object-oriented features
- Try other languages like Java, TypeScript, or Go to compare syntax
- Use the "Load Example" button to see C#-specific code samples
- Use Ctrl+Enter to quickly run your code
Interacting with the User
Professional apps aren't just one-way; they interact with users. We use Console.ReadLine() to capture input.
using System; class Program { static void Main() { Console.Write("Enter your name: "); string userName = Console.ReadLine(); Console.WriteLine("Hello, " + userName + "! Welcome to the course."); } }
Objective: Create a "User Profile Generator".
Build a console application that asks the user for the following four pieces of information:
- Full Name
- Age
- Country of Residence
- Favorite Programming Language
Once the input is collected, the program should print a professional summary: "User Profile: [Name], [Age] years old, from [Country], specializing in [Language]."
Variables & Data Types
Understanding Variables
In programming, a variable is a named storage location in the computer's memory. Think of it as a labeled box where you can store a value, and then retrieve or change that value later in your program.
C# is a Strongly Typed language. This means that every variable must have a defined type. Once a variable is declared as an integer, you cannot store a string in it. This prevents a huge category of bugs that occur in "loosely typed" languages like JavaScript.
Primitive Data Types
C# provides a variety of built-in types to handle different kinds of data. Choosing the right type is critical for performance and memory efficiency.
| Type | Storage Size | Description | Example |
|---|---|---|---|
int |
4 bytes | Whole numbers (Integers) | int age = 25; |
double |
8 bytes | Decimal numbers (Floating point) | double price = 19.99; |
decimal |
16 bytes | High-precision decimals (Financial) | decimal tax = 15.50m; |
bool |
1 byte | True or False values | bool isComplete = true; |
char |
2 bytes | Single character (Unicode) | char grade = 'A'; |
string |
Variable | Sequence of characters (Text) | string name = "Alice"; |
Never use double or float for financial calculations. They use binary floating-point math which can cause tiny rounding errors (e.g., 0.1 + 0.2 = 0.30000000000000004). Always use decimal for money to ensure absolute precision.
The var Keyword (Implicit Typing)
C# allows you to use the var keyword. This tells the compiler to infer (guess) the type based on the value assigned to it.
var message = "Hello World"; // Compiler knows this is a string var count = 10; // Compiler knows this is an int
Professional Tip: Use var when the type is obvious (e.g., var list = new List<string>();). Avoid using var if it makes the code harder for other developers to read.
Type Casting
Sometimes you need to convert a value from one type to another. This is called Casting.
1. Implicit Casting (Automatic)
Happens when you move a smaller type to a larger type. No data loss occurs.
int myInt = 9; double myDouble = myInt; // Automatic: int becomes double
2. Explicit Casting (Manual)
Required when moving a larger type to a smaller type. This can lead to data loss (truncation).
double myDouble = 9.78; int myInt = (int)myDouble; // Manual: 9.78 becomes 9 (decimals are dropped)
Constants and Read-Only Fields
If a value should never change during the execution of the program, use the const keyword. This improves performance and prevents accidental bugs.
const double Pi = 3.14159; const string CompanyName = "TechCorp Inc"; // Pi = 3.15; // ❌ This will cause a compile-time error
Professional Naming Conventions
In the professional world, following the Microsoft C# Coding Conventions is mandatory for teamwork.
- camelCase: Used for local variables and method parameters.
Example:int userAge = 25; - PascalCase: Used for Classes, Methods, and Constants.
Example:public class UserProfile { } - Avoid: Single letter names like
a,b,x. Use descriptive names liketotalInvoiceAmount.
Scenario: You are building a simple billing system for a client.
Requirements: Create a program that does the following:
- Declare a
const decimalfor a Tax Rate (e.g., 0.15 for 15%). - Ask the user to input the Product Name (string).
- Ask the user to input the Price of the product (decimal).
- Ask the user for the Quantity (int).
- Calculate the Subtotal (Price × Quantity).
- Calculate the Tax Amount (Subtotal × Tax Rate).
- Calculate the Final Total (Subtotal + Tax Amount).
- Print a professional receipt including all the above values.
Hint: Use decimal.Parse(Console.ReadLine()) to convert user input to a decimal.
Operators & Expressions
What are Operators & Expressions?
An expression is a combination of operators, variables, and values that are evaluated to produce a single result. An operator is a symbol that tells the compiler to perform a specific mathematical or logical manipulation.
Every expression in C# results in a value. For example, 5 + 2 is an expression that evaluates to the integer 7. In professional software, we aim for "clean" expressions—avoiding overly complex one-liners that are hard for other developers to read.
1. Arithmetic Operators
Used to perform standard mathematical operations.
| Operator | Name | Description | Example (int a=10, b=3) |
|---|---|---|---|
+ |
Addition | Adds two values | a + b // 13 |
- |
Subtraction | Subtracts one value from another | a - b // 7 |
* |
Multiplication | Multiplies two values | a * b // 30 |
/ |
Division | Divides one value by another | a / b // 3 |
% |
Modulus | Returns the division remainder | a % b // 1 |
In C#, if you divide two integers, the result is always an integer. Any remainder is simply discarded (truncated).
Example: int result = 5 / 2; will give you 2, not 2.5. To get a decimal result, at least one number must be a double or decimal: double result = 5.0 / 2; // 2.5.
2. Comparison (Relational) Operators
These operators compare two values and always return a bool (true or false). They are the foundation of logic in programming.
==Equal to!=Not equal to>Greater than<Less than>=Greater than or equal to<=Less than or equal to
3. Logical Operators
Logical operators are used to combine multiple comparison expressions.
- AND (
&&): Returns true only if both statements are true. - OR (
||): Returns true if at least one statement is true. - NOT (
!): Reverses the result (true becomes false, false becomes true).
C# uses "short-circuiting." In an && operation, if the first condition is false, C# doesn't even check the second condition because the whole thing is already guaranteed to be false. This is used by professionals to prevent crashes (e.g., checking if an object is not null before accessing its properties).
4. Assignment & Compound Operators
Instead of writing x = x + 5, professionals use compound assignments for brevity and clarity.
int score = 100; score += 10; // Same as: score = score + 10; (110) score -= 5; // Same as: score = score - 5; (105) score *= 2; // Same as: score = score * 2; (210) score /= 10; // Same as: score = score / 10; (21)
5. Professional "Syntactic Sugar"
Modern C# provides shorthand operators that make code cleaner and more readable.
The Ternary Operator (?:)
A compact way to write a simple If-Else statement.
int age = 20; string status = (age >= 18) ? "Adult" : "Minor"; // If age >= 18 is true, result is "Adult". Otherwise, "Minor".
The Null-Coalescing Operator (??)
Used to provide a default value if a variable is null.
string input = null; string displayName = input ?? "Guest User"; // If input is null, displayName becomes "Guest User".
Scenario: You are coding the checkout logic for an online store.
Requirements: Build a program that calculates the final price based on these rules:
- Ask user for the Order Total (decimal).
- Ask user if they have a Discount Coupon (bool/string).
- Rule 1: If the Order Total is over $100, they get a 10% discount.
- Rule 2: If they have a coupon AND the order is over $50, they get an additional $5 off.
- Rule 3: If the final total is under $20, add a $5 shipping fee. If it's $20 or more, shipping is free.
- Final Output: Display the Original Price, Total Discounts applied, and the Final Amount to pay.
Challenge: Try using a Ternary operator to determine the shipping fee message (e.g., "Shipping: Free" or "Shipping: $5").
Control Flow: Decision Making
What is Control Flow?
By default, code executes line-by-line from top to bottom. Control Flow allows us to break this linear path, skipping sections of code or executing specific blocks based on whether a condition is true or false.
In the industry, we track "Cyclomatic Complexity"—a measure of how many independent paths there are through your code. The more nested if statements you have, the higher the complexity, and the harder the code is to test and maintain. Professional code aims for low complexity.
1. Conditional Branching (If, Else If, Else)
The if statement is the most basic form of decision-making. It evaluates a boolean expression and executes a block of code if the result is true.
int userAge = 20; if (userAge >= 21) { Console.WriteLine("Access Granted: Full Access."); } else if (userAge >= 18) { Console.WriteLine("Access Granted: Limited Access."); } else { Console.WriteLine("Access Denied: Underage."); }
Professional Tip: Always use curly braces { } even for single-line statements. It prevents bugs during future code edits.
2. The Switch Statement
When you have a single variable that could be one of many distinct values, a switch statement is cleaner and more performant than multiple else if blocks.
string role = "Admin"; switch (role) { case "Admin": Console.WriteLine("Full System Access."); break; case "Editor": Console.WriteLine("Content Management Access."); break; case "Guest": Console.WriteLine("Read-Only Access."); break; default: Console.WriteLine("Unknown Role: Access Denied."); break; }
The break keyword is mandatory. Without it, the code would "fall through" to the next case, which usually causes a compiler error in C#.
3. Modern C#: Switch Expressions (C# 8.0+)
Professional developers rarely use the old switch statement for simple assignments. They use Switch Expressions, which are more concise and return a value directly.
int dayNumber = 3; string dayName = dayNumber switch { 1 => "Monday", 2 => "Tuesday", 3 => "Wednesday", 4 => "Thursday", 5 => "Friday", _ => "Weekend" // The underscore (_) is the default case }; Console.WriteLine($"Today is {dayName}");
4. Professional Pattern: The Guard Clause
Beginners often write "nested" code that drifts to the right (Arrow Code). Professionals use Guard Clauses to handle errors early and "flatten" the code.
if (user != null) {
if (user.IsActive) {
if (user.HasPermission) {
// Do the actual work here...
}
}
}
✅ The "Professional" Way (Guard Clauses)
if (user == null) return;
if (!user.IsActive) return;
if (!user.HasPermission) return;
// Do the actual work here... (The code stays flat!)
Scenario: You are building a security module for a corporate building.
Requirements: Create a program that asks for the user's Employee ID and Security Clearance Level (1 to 5).
- Requirement 1: If the Employee ID is empty, print "Error: ID Required" and stop. (Use a Guard Clause).
- Requirement 2: Use a Switch Expression to determine the Access Level based on the Clearance Level:
- 1 $\rightarrow$ "Public Area Only"
- 2 $\rightarrow$ "Office Area"
- 3 $\rightarrow$ "Server Room"
- 4 $\rightarrow$ "Executive Suite"
- 5 $\rightarrow$ "Top Secret Vault"
- Any other number $\rightarrow$ "Invalid Clearance Level"
- Requirement 3: If the Clearance Level is 5 AND the Employee ID is "ADMIN-001", print "Welcome, Director." Otherwise, print the assigned Access Level.
Loops: Mastering Iteration
What is Iteration?
Iteration is the process of executing a block of code repeatedly until a specific condition is met. In professional software, loops are used for processing data sets, polling for status changes, or repeating user prompts until valid input is received.
When you write a loop, you are consuming CPU cycles. A single loop through a list of $n$ items has a time complexity of O(n). However, if you put a loop inside another loop (nested loops), the complexity becomes O(n²). Professionals always strive to minimize nested loops to prevent "performance bottlenecks" as data grows.
1. The for Loop
The for loop is best used when you know exactly how many times the code should run. It is a "counter-driven" loop.
// Structure: (Initialization; Condition; Iterator) for (int i = 0; i < 5; i++) { Console.WriteLine($"Processing item number: {i}"); }
Breakdown:
1. int i = 0: Starts the counter.
2. i < 5: The loop runs as long as this is true.
3. i++: Increases the counter by 1 after each loop.
2. The while and do-while Loops
These are "condition-driven" loops. They are used when you don't know how many times the loop will run, but you know when it should stop.
The while Loop (Check then Act)
Checks the condition before executing the block. If the condition is false at the start, the code inside never runs.
bool isRunning = true; while (isRunning) { Console.WriteLine("System is scanning..."); // Logic to eventually set isRunning = false; }
The do-while Loop (Act then Check)
Executes the block once first, then checks the condition. This guarantees the code runs at least once.
string input; do { Console.WriteLine("Please enter 'exit' to stop:"); input = Console.ReadLine(); } while (input != "exit");
3. The foreach Loop (Industry Standard)
The foreach loop is the most common loop in professional C# development. It is used to iterate through collections (Arrays, Lists, Dictionaries) without needing an index counter.
string[] employees = { "Alice", "Bob", "Charlie" }; foreach (var name in employees) { Console.WriteLine($"Sending email to: {name}"); }
You cannot modify a collection while iterating through it with a foreach loop. If you try to add or remove an item from the list inside a foreach, C# will throw a InvalidOperationException. To modify a list while looping, use a standard for loop and iterate backwards.
4. Loop Control: break and continue
Professionals use these keywords to optimize loops and handle edge cases.
- break: Immediately terminates the loop and jumps to the code following the loop.
- continue: Skips the current iteration and jumps immediately to the next cycle of the loop.
for (int i = 1; i <= 10; i++) { if (i == 3) continue; // Skip 3 if (i == 7) break; // Stop entirely at 7 Console.WriteLine(i); // Output: 1, 2, 4, 5, 6 }
Scenario: You are processing a list of server response times (in milliseconds). You need to analyze the data and filter out "noise".
Requirements:
- Create an array of integers representing response times:
{ 120, 450, 80, -10, 1100, 90, 300, -5, 150 }. - Use a
foreachloop to iterate through the times. - Rule 1 (Data Cleaning): If a response time is negative, it's an error. Use
continueto skip it. - Rule 2 (Critical Failure): If a response time exceeds 1000ms, the server is considered "Crashed". Use
breakto stop processing immediately. - Rule 3 (Analysis): Calculate the total sum of all valid response times processed.
- Final Output: Print the total sum and the number of valid servers processed before the crash (or end of list).
Methods & Parameters
What Are Methods?
Methods are reusable blocks of code that perform a specific task. Instead of writing the same logic multiple times, we place that logic inside a method and call it whenever needed.
Methods help make programs:
- Cleaner and easier to read
- Reusable and modular
- Easier to debug and maintain
- More organized in large applications
void SayHello() { Console.WriteLine("Hello World"); }
Once defined, the method can be called anywhere in the program:
SayHello(); SayHello(); SayHello();
Defining Methods
A method definition usually contains:
- Access modifier (optional)
- Return type
- Method name
- Parameters
- Method body
static int Add(int x, int y) => x + y; void Greet(string name, string title = "Dr.") { Console.WriteLine($"Hello {title} {name}"); }
Understanding Return Types
The return type tells C# what kind of value the method sends back.
int→ returns a whole numberdouble→ returns decimal valuesstring→ returns textbool→ returns true or falsevoid→ returns nothing
int Square(int number) { return number * number; }
Calling the method:
int result = Square(5);
Console.WriteLine(result);
Method Parameters
Parameters allow methods to receive data from outside. They act like variables that belong to the method.
void DisplayUser(string username, int age) { Console.WriteLine(username); Console.WriteLine(age); }
Passing arguments into the method:
DisplayUser("Alex", 22);
Default Parameters
Default parameters provide fallback values when an argument is not supplied. This makes methods more flexible.
void Welcome(string name = "Guest") { Console.WriteLine($"Welcome {name}"); }
Welcome();
Welcome("Emma");
Expression-Bodied Methods
Small methods can be shortened using the lambda-style arrow syntax. This creates cleaner and shorter code.
int Multiply(int a, int b) => a * b;
Method Overloading
C# allows multiple methods with the same name as long as their parameters are different.
int Add(int a, int b) { return a + b; } double Add(double a, double b) { return a + b; }
The compiler automatically selects the correct version.
Pass By Value
By default, C# passes arguments by value. This means the method receives a copy of the data.
void ChangeNumber(int num) { num = 100; } int value = 10; ChangeNumber(value); Console.WriteLine(value);
Output:
10
The original variable remains unchanged because only a copy was modified.
Using ref Parameters
The ref keyword passes variables by reference,
allowing the method to directly modify the original variable.
void Increase(ref int number) { number++; } int score = 5; Increase(ref score); Console.WriteLine(score);
Using out Parameters
The out keyword is used when a method needs to return
multiple values.
void GetValues(out int x, out int y) { x = 10; y = 20; } GetValues(out int a, out int b); Console.WriteLine(a); Console.WriteLine(b);
Local Methods
Methods can also exist inside another method. These are called local methods.
void MainMethod() { void PrintMessage() { Console.WriteLine("Inside Local Method"); } PrintMessage(); }
Best Practices
- Keep methods short and focused
- Use meaningful method names
- Avoid methods that do too many tasks
- Reuse methods whenever possible
- Use parameters instead of hardcoded values
Common Mistakes
- Forgetting the return statement
- Using the wrong return type
- Passing incorrect argument types
- Creating methods with too many parameters
- Not understanding value vs reference passing
Mini Practice
Try creating the following methods yourself:
- A method that calculates area of a rectangle
- A method that checks if a number is even
- A method that prints a full name
- A method with a default parameter
- A method using
reforout
Collections & LINQ
What Are Collections?
Collections are data structures used to store and manage groups of objects. Instead of creating multiple individual variables, collections allow us to organize related data efficiently.
C# provides several built-in collection types that are powerful, flexible, and easy to use.
- Arrays
- Lists
- Dictionaries
- Queues
- Stacks
- HashSets
Why Use Collections?
Collections help developers work with large amounts of data dynamically. They make programs cleaner and more scalable.
- Store multiple values together
- Add or remove data dynamically
- Search and sort efficiently
- Loop through items easily
- Organize related information
Working with Lists
A List<T> is one of the most commonly used collections in C#.
Unlike arrays, lists can grow and shrink dynamically.
var numbers = new List<int> { 10, 20, 30, 40 }; numbers.Add(50); numbers.RemoveAt(0);
After removing the first element, the list becomes:
20, 30, 40, 50
Adding Items to a List
Use the Add() method to insert new items into a list.
var fruits = new List<string>(); fruits.Add("Apple"); fruits.Add("Banana"); fruits.Add("Orange");
Accessing List Elements
List items are accessed using indexes.
Indexes start from 0.
Console.WriteLine(fruits[0]); Console.WriteLine(fruits[1]);
Looping Through Lists
Lists are commonly used with loops to process every item.
foreach (var item in fruits) { Console.WriteLine(item); }
Useful List Methods
| Method | Description |
|---|---|
| Add() | Adds a new item |
| Remove() | Removes a specific item |
| RemoveAt() | Removes item by index |
| Contains() | Checks if item exists |
| Clear() | Removes all items |
| Count | Returns total number of items |
Using Dictionaries
Dictionaries store data as key-value pairs. They are useful when each item has a unique identifier.
var students = new Dictionary<int, string>(); students.Add(1, "John"); students.Add(2, "Emma"); Console.WriteLine(students[1]);
Understanding LINQ
LINQ stands for Language Integrated Query. It allows developers to query collections using simple and readable syntax.
LINQ works with:
- Lists
- Arrays
- Dictionaries
- Databases
- XML data
Introduction to LINQ
LINQ (Language Integrated Query) allows you to query collections like SQL.
var highScores = numbers
.Where(n => n > 25)
.OrderByDescending(n => n);
This query:
- Filters numbers greater than 25
- Sorts them in descending order
The Where() Method
Where() filters data based on a condition.
var evenNumbers = numbers.Where(n => n % 2 == 0);
Only even numbers will be selected.
The Select() Method
Select() transforms data into another form.
var squared = numbers.Select(n => n * n);
This creates a new collection with squared values.
Sorting Data with LINQ
LINQ provides easy methods for sorting collections.
var ascending = numbers.OrderBy(n => n); var descending = numbers.OrderByDescending(n => n);
Finding Data
LINQ can quickly search for matching values.
var firstLargeNumber = numbers.First(n => n > 25);
The first number greater than 25 will be returned.
Counting Items
The Count() method returns the total number of matching items.
int total = numbers.Count(); int evenCount = numbers.Count(n => n % 2 == 0);
Combining LINQ Methods
Multiple LINQ methods can be chained together for powerful queries.
var result = numbers
.Where(n => n > 10)
.OrderBy(n => n)
.Select(n => n * 2);
Deferred Execution
Most LINQ queries use deferred execution. This means the query runs only when the data is actually used.
var query = numbers.Where(n => n > 20);
Console.WriteLine(query.Count());
Common LINQ Methods
| Method | Purpose |
|---|---|
| Where() | Filter data |
| Select() | Transform data |
| OrderBy() | Sort ascending |
| OrderByDescending() | Sort descending |
| First() | Get first matching item |
| Count() | Count items |
| Any() | Check if data exists |
Best Practices
- Use collections instead of many separate variables
- Choose the correct collection type for the task
- Keep LINQ queries readable
- Avoid overly complex chained queries
- Use meaningful variable names
Common Mistakes
- Using the wrong collection type
- Forgetting indexes start at 0
- Modifying collections during iteration
- Writing unreadable LINQ chains
- Ignoring null values in queries
Mini Practice
Try creating the following:
- A list of student names
- A dictionary of product prices
- A LINQ query that finds even numbers
- A query that sorts numbers descending
- A query using both
Where()andSelect()
Strings & Formatting
What Are Strings?
A string is a sequence of characters used to store text. Strings are one of the most commonly used data types in C#.
Examples of strings:
- Names
- Email addresses
- Messages
- User input
- File paths
string name = "John"; string message = "Welcome to C#";
Creating Strings
Strings are written inside double quotation marks.
string city = "London"; string language = "C#";
String Manipulation
C# provides many built-in methods for modifying and working with strings.
string text = " C# Programming "; Console.WriteLine(text.Trim().ToUpper()); Console.WriteLine(text.Contains("C#"));
This example:
- Removes extra spaces using
Trim() - Converts text to uppercase using
ToUpper() - Checks if text contains a value using
Contains()
Common String Methods
| Method | Description |
|---|---|
| ToUpper() | Converts text to uppercase |
| ToLower() | Converts text to lowercase |
| Trim() | Removes extra spaces |
| Contains() | Checks for matching text |
| Replace() | Replaces text |
| Substring() | Extracts part of a string |
| StartsWith() | Checks starting characters |
| EndsWith() | Checks ending characters |
Converting Case
Strings can easily be converted between uppercase and lowercase.
string word = "Programming"; Console.WriteLine(word.ToUpper()); Console.WriteLine(word.ToLower());
Replacing Text
The Replace() method changes parts of a string.
string sentence = "I like Java"; sentence = sentence.Replace("Java", "C#"); Console.WriteLine(sentence);
Extracting Text
The Substring() method extracts a portion of a string.
string value = "Programming"; Console.WriteLine(value.Substring(0, 4));
Output:
Prog
Escaping Characters
Escape characters allow special characters inside strings.
Console.WriteLine("She said \"Hello\""); Console.WriteLine("C:\\Projects\\App");
Verbatim Strings
Verbatim strings use the @ symbol to preserve formatting.
string path = @" C:\Projects\MyApp\data.txt"; Console.WriteLine(path);
String Concatenation
Concatenation means joining strings together.
string firstName = "John"; string lastName = "Doe"; string fullName = firstName + " " + lastName; Console.WriteLine(fullName);
String Interpolation
String interpolation is a cleaner way to insert variables into strings.
Console.WriteLine($"Date: {DateTime.Now:d}"); Console.WriteLine($"Price: {19.99:C}"); // Currency
The $ symbol allows variables and expressions inside curly braces.
Formatting Values
C# supports formatting numbers, dates, and currency values.
double price = 99.95; Console.WriteLine($"{price:C}"); Console.WriteLine($"{price:N2}"); Console.WriteLine($"{price:P}");
| Format | Meaning |
|---|---|
| C | Currency |
| N2 | Number with 2 decimals |
| P | Percentage |
| d | Short date format |
Working with String Length
The Length property returns the number of characters.
string username = "Admin"; Console.WriteLine(username.Length);
Splitting Strings
The Split() method separates text into multiple parts.
string data = "HTML,CSS,JavaScript"; var skills = data.Split(','); foreach (var skill in skills) { Console.WriteLine(skill); }
Comparing Strings
Strings can be compared using comparison operators or helper methods.
string a = "C#"; string b = "c#"; Console.WriteLine(a == b); Console.WriteLine(a.Equals(b, StringComparison.OrdinalIgnoreCase));
String Immutability
Strings in C# are immutable. This means their contents cannot be changed after creation.
Methods like Replace() or ToUpper()
create new strings instead of modifying the original one.
string textValue = "hello"; string upper = textValue.ToUpper(); Console.WriteLine(textValue); Console.WriteLine(upper);
Best Practices
- Use meaningful variable names
- Prefer string interpolation over concatenation
- Trim user input when necessary
- Use formatting for readable output
- Keep string operations simple and readable
Common Mistakes
- Forgetting escape characters
- Using invalid indexes in Substring()
- Ignoring whitespace in user input
- Comparing strings with incorrect casing
- Confusing immutable behavior
Mini Practice
Try creating programs that:
- Convert text to uppercase
- Replace words in a sentence
- Display formatted prices
- Split a CSV string into values
- Create a formatted welcome message using interpolation
Object-Oriented Programming
Welcome, class. Today we deep-dive into the foundational architecture of scalable software design: Object-Oriented Programming (OOP). As software systems grow in complexity, linear, procedural code inevitably collapses under its own weight. OOP provides us with a framework to manage this complexity by partitioning our programs into self-contained, reusable modules modeled after real-world entities.
The Conceptual Paradigm: Blueprints vs. Artifacts
Before looking at the syntax, you must master the fundamental distinction between a Class and an Object:
- The Class (The Blueprint): This is an abstract data type. It defines the structure, capabilities, and rules of engagement, but it consumes no operational memory for data storage. It is merely a design.
- The Object (The Instance): This is the concrete artifact generated from that blueprint. It lives dynamically within your system's RAM, maintaining its own unique state.
Consider the architectural example below written in C#. Here, we define a baseline archetype (Person) and a specialized extension of that archetype (Developer).
public class Person { public string Name { get; set; } public virtual void Work() => Console.WriteLine("Working..."); } public class Developer : Person { public override void Work() => Console.WriteLine("Coding..."); }
Anatomy of the Mechanics: Inheritance & Polymorphism
Let us break down the underlying mechanics of this code slice. Notice the use of the : operator in Developer : Person. This establishes an IS-A relationship (Inheritance). A Developer is a Person, meaning it automatically inherits the Name property without explicit redeclaration.
However, the real magic happens within the execution behavior, driven by two critical keywords:
virtual: Declared in the base class, this signals to the compiler that this method's behavior is fluid and can be intercepted by derived child classes.override: Declared in the subclass, this actively intercepts the runtime execution path, substituting the base behavior with a specialized implementation.
Advanced Execution: Dynamic Binding in Action
To fully appreciate why this matters to a software architect, look at how the runtime engine processes these objects when grouped together. Because of polymorphism, a collection typed to the base class can hold any derived class instance seamlessly.
List<Person> team = new List<Person>() { new Person { Name = "Professor Smith" }, new Developer { Name = "Grace Hopper" } }; foreach (var member in team) { Console.Write(member.Name + " execution path: "); member.Work(); }
When this loop runs, the output demonstrates Dynamic Binding (or late binding). The system determines which method to call at runtime based on the actual object type, not the variable type:
Professor Smith execution path: Working... Grace Hopper execution path: Coding...
Professor's Lab Task: Expanding the Ecosystem
To reinforce today's lecture, you must complete a practical coding task. Your goal is to introduce a third tier to our organizational hierarchy that introduces unique tracking and alters behavior appropriately.
Your Instructions:
- Create a new class named
Managerthat inherits directly fromPerson. - Add an exclusive property to the
Managerclass:TeamSize(an integer type). - Override the
Work()method so that it outputs:"Managing a team of [TeamSize] people..."instead of the generic response.
public class Manager : Person { // 1. Task: Define your TeamSize property here // 2. Task: Override the Work() method using string interpolation }
Verify your solution by creating an instance of your Manager, assigning it a TeamSize of 5, adding it to the team list created above, and confirming that the output shifts dynamically at runtime.
Exceptions & File I/O
Handling Errors
try { int x = int.Parse(Console.ReadLine()); } catch (FormatException ex) { Console.WriteLine("Invalid number format."); } finally { Console.WriteLine("Done."); }
Reading/Writing Files
File.WriteAllText("log.txt", "Hello C#"); string content = File.ReadAllText("log.txt");
The .NET Ecosystem
NuGet & Libraries
Use dotnet add package to install community libraries like Newtonsoft.Json.
Asynchronous Programming
public async Task<string> GetDataAsync() { var client = new HttpClient(); return await client.GetStringAsync("https://api.example.com"); }
Capstone Project: Task Manager
Build a console-based Task Manager that uses everything we've learned: Lists, LINQ, OOP, and File I/O.
// Project requirements: // 1. Add/Remove tasks // 2. Mark tasks as complete // 3. Save tasks to tasks.json // 4. Filter tasks using LINQ
Async & Await
Content coming soon...
Delegates & Events
Content coming soon...
Generics & Interfaces
Content coming soon...
Entity Framework & Databases
Content coming soon...
Unit Testing (xUnit)
Content coming soon...
Final Project — .NET Web API
Content coming soon...