C# Programming Labs

Master inheritance, interfaces, and asynchronous programming patterns in C#.

Advanced OOP & Async - Module 4

Learn inheritance, interfaces, and modern async/await patterns.

Lab 10: Inheritance & Polymorphism
Advanced
Coding Challenge
Your Task: Create a class hierarchy demonstrating inheritance and polymorphism with a base Animal class and derived Dog and Cat classes.

Detailed Requirements:
1. Create a base class Animal:
class Animal { public string Name { get; set; } public Animal(string name) { Name = name; } // Virtual method - can be overridden public virtual void Speak() { Console.WriteLine($"{Name} makes a sound."); } } The virtual keyword allows derived classes to override this method.

2. Create derived classes:
class Dog : Animal // Dog inherits from Animal { public Dog(string name) : base(name) { } // Call base constructor public override void Speak() // Override the virtual method { Console.WriteLine($"{Name} barks: Woof!"); } } class Cat : Animal { public Cat(string name) : base(name) { } public override void Speak() { Console.WriteLine($"{Name} meows: Meow!"); } } Use : base(name) to call the parent constructor.

3. Demonstrate polymorphism:
// Polymorphism: treat derived objects as base type Animal[] animals = new Animal[] { new Dog("Rex"), new Cat("Whiskers"), new Animal("Unknown") }; foreach (Animal animal in animals) { animal.Speak(); // Calls appropriate override! }

💡 Pro Tips:
• Use abstract class/methods when base shouldn't be instantiated
• sealed prevents further inheritance
• base.Method() calls parent implementation
• Prefer composition over inheritance when possible
• Use is and as for type checking: if (animal is Dog d) { }

Expected Output:
Rex barks: Woof! Whiskers meows: Meow! Unknown makes a sound.

Requirements Checklist

Create base Animal class with Name property
Add virtual Speak() method to Animal
Create Dog class that inherits from Animal
Create Cat class that inherits from Animal
Override Speak() in derived classes
Demonstrate polymorphism with array
Output
// Click "Run Code" to compile and execute
Hints & Tips
• Inherit: class Dog : Animal { }
• Virtual method: public virtual void Speak() { }
• Override: public override void Speak() { }
• Call base constructor: public Dog(string name) : base(name) { }
• Polymorphism: Animal[] animals = new Animal[] { new Dog("Rex") };
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 11: Interfaces
Advanced
Coding Challenge
Your Task: Create interfaces to define contracts and implement them in classes to demonstrate interface-based polymorphism.

Detailed Requirements:
1. Create an interface:
interface IShape { double GetArea(); // Method signature (no implementation) double GetPerimeter(); string Name { get; } // Property signature } Interfaces define WHAT a class must do, not HOW. By convention, interface names start with "I".

2. Implement the interface in classes:
class Rectangle : IShape { public double Width { get; set; } public double Height { get; set; } public string Name => "Rectangle"; public Rectangle(double width, double height) { Width = width; Height = height; } public double GetArea() => Width * Height; public double GetPerimeter() => 2 * (Width + Height); } class Circle : IShape { public double Radius { get; set; } public string Name => "Circle"; public Circle(double radius) { Radius = radius; } public double GetArea() => Math.PI * Radius * Radius; public double GetPerimeter() => 2 * Math.PI * Radius; }

3. Use interface as type:
IShape[] shapes = new IShape[] { new Rectangle(5, 3), new Circle(4) }; foreach (IShape shape in shapes) { Console.WriteLine($"{shape.Name}: Area = {shape.GetArea():F2}"); }

💡 Pro Tips:
• A class can implement multiple interfaces: class Foo : IBar, IBaz
• Interfaces can inherit from other interfaces
• Default interface methods (C# 8+) allow implementations in interfaces
• Use interfaces for dependency injection and testability
• Prefer interfaces over abstract classes for contracts

Expected Output:
Rectangle: Area = 15.00, Perimeter = 16.00 Circle: Area = 50.27, Perimeter = 25.13

Requirements Checklist

Create IShape interface with GetArea() and GetPerimeter()
Add Name property to interface
Create Rectangle class implementing IShape
Create Circle class implementing IShape
Implement all interface members
Use IShape array for polymorphism
Output
// Click "Run Code" to compile and execute
Hints & Tips
• Interface: interface IShape { double GetArea(); }
• Implement: class Rectangle : IShape { }
• Property in interface: string Name { get; }
• Expression body: public double GetArea() => Width * Height;
• Use Math.PI for circle calculations
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 12: Async/Await & Tasks
Expert
Coding Challenge
Your Task: Learn asynchronous programming with async/await to write non-blocking code that handles long-running operations efficiently.

Detailed Requirements:
1. Create an async method:
static async Task<string> FetchDataAsync() { Console.WriteLine("Starting fetch..."); // Simulate network delay (non-blocking) await Task.Delay(2000); // 2 second delay Console.WriteLine("Fetch complete!"); return "Data from server"; } async marks the method as asynchronous. await pauses execution until the task completes without blocking the thread.

2. Return types for async methods:
// Returns a value async Task<string> GetStringAsync() { ... } // No return value async Task DoWorkAsync() { ... } // Fire and forget (use sparingly!) async void EventHandler() { ... }

3. Call async methods:
static async Task Main() // async Main supported in C# 7.1+ { Console.WriteLine("Program started"); // Await the async method string result = await FetchDataAsync(); Console.WriteLine($"Result: {result}"); Console.WriteLine("Program ended"); }

4. Run multiple tasks in parallel:
// Start multiple tasks Task<string> task1 = FetchDataAsync(); Task<string> task2 = FetchDataAsync(); // Wait for all to complete await Task.WhenAll(task1, task2); // Or wait for any one Task completedTask = await Task.WhenAny(task1, task2);

💡 Pro Tips:
• Always use async/await for I/O operations
• Avoid async void except for event handlers
• Use ConfigureAwait(false) in library code
• Handle exceptions with try-catch around await
• Use CancellationToken to cancel long operations

Expected Output:
Program started Starting fetch... Fetch complete! Result: Data from server Program ended

Requirements Checklist

Create async method with Task return type
Use await keyword
Use Task.Delay for simulation
Return value from async method
Use async Main method
Console output showing async flow
Output
// Click "Run Code" to compile and execute
Hints & Tips
• Async method: static async Task<string> FetchAsync() { }
• Await: await Task.Delay(1000);
• Return: return "result"; (automatically wrapped in Task)
• Async Main: static async Task Main() { }
• Call async: string r = await FetchAsync();
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below