C# OOP (Questions Only)

C# Question Bank

OOP Concepts | 10 Scenario Questions (5 Moderate + 5 Complex) — Questions Only

How to use:
1) For each question, paste/modify the Sample Input (it is intentionally complex: spaces, special chars, quotes, emoji, unicode).
2) Copy the boilerplate code and run it as a Console App.
3) Implement ONLY the methods marked with // ✅ TODO.
4) Do not write answers here. This page is questions-only.
Moderate: 5 Complex: 5 Focus: Encapsulation, Inheritance, Polymorphism, Abstraction, Interfaces, Events, Patterns
1

Bank Account with Encapsulation + Validation

OOPEncapsulationPropertiesValidationModerate

Scenario: You are building a bank account module for a console-based finance app. What to implement: - Create a BankAccount class with private fields and safe public methods. - Validate deposits/withdrawals and block invalid operations. - Parse complex input lines (spaces, quotes, special chars) to drive the flow. ✅ Student task: - Implement only the TODO methods: 1) BankAccount.Deposit(...) 2) BankAccount.Withdraw(...) 3) InputParser.ParseAmount(...) - Main() should remain unchanged. Ask yourself: - What should happen when input contains currency symbols, commas, and spaces?

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console, Exception

namespace ItTechGenie.M1.OOP.Q1
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");       // ask user for input
            var lines = ConsoleInput.ReadLines();                               // read multi-line input

            var engine = new BankEngine();                                      // orchestrates operations
            engine.Run(lines);                                                  // execute commands
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            // Read until empty line for easy testing.
            var list = new System.Collections.Generic.List<string>();           // store lines
            while (true)
            {
                var line = Console.ReadLine();                                  // read one line
                if (string.IsNullOrWhiteSpace(line)) break;                     // stop on empty
                list.Add(line);                                                 // add line
            }
            return list.ToArray();                                              // return array
        }
    }

    public class BankEngine
    {
        private readonly System.Collections.Generic.Dictionary<int, BankAccount> _accounts = new(); // store accounts

        public void Run(string[] lines)
        {
            foreach (var raw in lines)                                          // process each line
            {
                var cmd = Command.Parse(raw);                                   // parse command structure

                if (cmd.Name == "ACC_CREATE")                                   // create account
                {
                    int id = int.Parse(cmd.Get("id"));                          // parse id
                    string name = cmd.Get("name");                              // get name
                    decimal opening = InputParser.ParseAmount(cmd.Get("opening")); // parse amount with symbols
                    _accounts[id] = new BankAccount(id, name, opening);         // create and store
                }
                else if (cmd.Name == "ACC_DEPOSIT")                             // deposit
                {
                    int id = int.Parse(cmd.Get("id"));                          // id
                    decimal amt = InputParser.ParseAmount(cmd.Get("amount"));   // amount
                    _accounts[id].Deposit(amt, cmd.Get("note"));                // ✅ calls TODO
                }
                else if (cmd.Name == "ACC_WITHDRAW")                            // withdraw
                {
                    int id = int.Parse(cmd.Get("id"));                          // id
                    decimal amt = InputParser.ParseAmount(cmd.Get("amount"));   // amount
                    _accounts[id].Withdraw(amt, cmd.Get("note"));               // ✅ calls TODO
                }
                else if (cmd.Name == "PRINT")                                   // print summary
                {
                    int id = int.Parse(cmd.Get("id"));                          // id
                    Console.WriteLine(_accounts[id].GetSummary());              // output
                }
            }
        }
    }

    public class BankAccount
    {
        private decimal _balance;                                               // encapsulated balance
        public int Id { get; }                                                  // read-only id
        public string HolderName { get; }                                        // read-only name

        public BankAccount(int id, string holderName, decimal opening)
        {
            Id = id;                                                            // assign
            HolderName = holderName;                                            // assign
            _balance = opening;                                                 // set opening balance
        }

        // ✅ TODO: Student must implement only this method
        public void Deposit(decimal amount, string note)
        {
            // TODO:
            // - validate amount > 0
            // - update _balance
            // - print receipt line with note (note can contain spaces/special chars)
            throw new NotImplementedException();
        }

        // ✅ TODO: Student must implement only this method
        public void Withdraw(decimal amount, string note)
        {
            // TODO:
            // - validate amount > 0
            // - validate amount <= _balance
            // - update _balance
            // - print receipt line with note
            throw new NotImplementedException();
        }

        public string GetSummary()
        {
            return $"Account[{Id}] {HolderName} | Balance={_balance}";          // summary string
        }
    }

    public static class InputParser
    {
        // ✅ TODO: Student must implement only this method
        public static decimal ParseAmount(string raw)
        {
            // TODO:
            // - handle currency symbols (₹, $, etc.)
            // - handle commas: "10,500.75"
            // - handle spaces: "₹ 1,999.25"
            // - return decimal value
            throw new NotImplementedException();
        }
    }

    public class Command
    {
        public string Name { get; }                                             // command name
        private readonly System.Collections.Generic.Dictionary<string, string> _kv; // parameters

        private Command(string name, System.Collections.Generic.Dictionary<string, string> kv)
        {
            Name = name;                                                        // assign
            _kv = kv;                                                           // assign
        }

        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : ""; // safe get

        public static Command Parse(string line)
        {
            // Very small parser: COMMAND|k=v|k="v with spaces"
            var parts = line.Split('|');                                        // split parts
            var name = parts[0].Trim();                                         // command name
            var kv = new System.Collections.Generic.Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            for (int i = 1; i < parts.Length; i++)                              // read key-value tokens
            {
                var p = parts[i];                                               // token
                var idx = p.IndexOf('=');                                       // locate '='
                if (idx <= 0) continue;                                         // skip invalid
                var key = p.Substring(0, idx).Trim();                           // key
                var val = p.Substring(idx + 1).Trim();                          // value
                val = val.Trim().Trim('"');                                    // remove quotes
                kv[key] = val;                                                  // store
            }

            return new Command(name, kv);                                       // build
        }
    }
}
2

Payroll System using Inheritance + Polymorphism

OOPInheritancePolymorphismAbstract ClassModerate

Scenario: A payroll tool needs to support multiple employee types (Developer, Manager). Each employee calculates salary differently (polymorphism). What to implement: - Create an abstract Employee base class with CalculateSalary(). - Derived classes override the salary logic. - Parse complex input lines to add employees and run payroll. ✅ Student task: - Implement only TODO methods: 1) EmployeeFactory.Create(...) 2) Developer.CalculateSalary() 3) Manager.CalculateSalary() Note: Input contains spaces, special characters, and quoted values — keep parsing robust.

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console

namespace ItTechGenie.M1.OOP.Q2
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();                               // read multi-line input

            var payroll = new PayrollEngine();                                  // engine
            payroll.Run(lines);                                                 // execute
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new System.Collections.Generic.List<string>();           // collect lines
            while (true)
            {
                var line = Console.ReadLine();                                  // read
                if (string.IsNullOrWhiteSpace(line)) break;                     // stop
                list.Add(line);                                                 // store
            }
            return list.ToArray();                                              // return
        }
    }

    public class PayrollEngine
    {
        private readonly System.Collections.Generic.List<Employee> _employees = new(); // employee list

        public void Run(string[] lines)
        {
            foreach (var raw in lines)                                          // for each command
            {
                var cmd = Command.Parse(raw);                                   // parse

                if (cmd.Name == "EMP_ADD")                                      // add employee
                {
                    var emp = EmployeeFactory.Create(cmd);                       // ✅ TODO factory
                    _employees.Add(emp);                                        // store
                }
                else if (cmd.Name == "PAYROLL")                                 // run payroll
                {
                    Console.WriteLine("---- PAYROLL RUN ----");                 // header
                    foreach (var e in _employees)                               // for each employee
                    {
                        var salary = e.CalculateSalary();                       // ✅ polymorphic call
                        Console.WriteLine($"{e.Id} | {e.Name} | {e.Role} | Salary={salary}"); // print
                    }
                }
            }
        }
    }

    public abstract class Employee
    {
        public string Id { get; }                                               // employee id
        public string Name { get; }                                             // employee name
        public string Role { get; }                                             // role
        public decimal BasePay { get; }                                         // base pay
        public string Extra { get; }                                            // extra info (may contain spaces)

        protected Employee(string id, string name, string role, decimal basePay, string extra)
        {
            Id = id;                                                           // assign
            Name = name;                                                       // assign
            Role = role;                                                       // assign
            BasePay = basePay;                                                 // assign
            Extra = extra;                                                     // assign
        }

        public abstract decimal CalculateSalary();                               // polymorphic salary calc
    }

    public sealed class Developer : Employee
    {
        public Developer(string id, string name, decimal basePay, string extra)
            : base(id, name, "Developer", basePay, extra) { }                   // call base

        // ✅ TODO: Student must implement only this method
        public override decimal CalculateSalary()
        {
            // TODO:
            // - Developer: salary = BasePay + (BasePay * 0.10m) as skill bonus
            // - Extra text may include skill info, but you don't need to parse it
            throw new NotImplementedException();
        }
    }

    public sealed class Manager : Employee
    {
        public Manager(string id, string name, decimal basePay, string extra)
            : base(id, name, "Manager", basePay, extra) { }                     // call base

        // ✅ TODO: Student must implement only this method
        public override decimal CalculateSalary()
        {
            // TODO:
            // - Manager: salary = BasePay + 15000 allowance + (BasePay * 0.05m) performance bonus
            throw new NotImplementedException();
        }
    }

    public static class EmployeeFactory
    {
        // ✅ TODO: Student must implement only this method
        public static Employee Create(Command cmd)
        {
            // TODO:
            // - read role, id, name, base, extra
            // - create Developer or Manager based on role (case-insensitive)
            // - throw meaningful exception for unknown role
            throw new NotImplementedException();
        }
    }

    public class Command
    {
        public string Name { get; }                                             // cmd name
        private readonly System.Collections.Generic.Dictionary<string, string> _kv; // parameters

        private Command(string name, System.Collections.Generic.Dictionary<string, string> kv)
        {
            Name = name;                                                        // assign
            _kv = kv;                                                           // assign
        }

        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : ""; // safe get

        public static Command Parse(string line)
        {
            var parts = line.Split('|');                                        // split
            var name = parts[0].Trim();                                         // cmd
            var kv = new System.Collections.Generic.Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            for (int i = 1; i < parts.Length; i++)                              // read tokens
            {
                var p = parts[i];                                               // token
                var idx = p.IndexOf('=');                                       // find '='
                if (idx <= 0) continue;                                         // skip
                var key = p.Substring(0, idx).Trim();                           // key
                var val = p.Substring(idx + 1).Trim().Trim('"');               // value without quotes
                kv[key] = val;                                                  // store
            }

            return new Command(name, kv);                                       // build
        }
    }
}
3

Vehicle Rental using Interface + Inheritance

OOPInterfaceInheritanceCompositionModerate

Scenario: A vehicle rental business supports Car and Bike with different pricing rules. What to implement: - Use an IVehicle interface and two implementations (Car, Bike). - RentalEngine should rent/return and calculate bill. ✅ Student task: - Implement only TODO methods: 1) RentalEngine.CalculateBill(...) 2) Car.CalculateRate(...) 3) Bike.CalculateRate(...) Ask user: - Paste sample input with special chars/spaces for customer name, notes, and vehicle registration.

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console

namespace ItTechGenie.M1.OOP.Q3
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();                               // read user input

            var engine = new RentalEngine();                                    // create rental engine
            engine.Run(lines);                                                  // process input
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new System.Collections.Generic.List<string>();           // store lines
            while (true)
            {
                var line = Console.ReadLine();                                  // read line
                if (string.IsNullOrWhiteSpace(line)) break;                     // stop
                list.Add(line);                                                 // add
            }
            return list.ToArray();                                              // return
        }
    }

    public interface IVehicle
    {
        string Registration { get; }                                            // unique id
        string Brand { get; }                                                   // brand
        decimal BaseRatePerDay { get; }                                         // base rate
        decimal CalculateRate(int days);                                        // pricing rule
    }

    public abstract class VehicleBase : IVehicle
    {
        public string Registration { get; }                                     // reg
        public string Brand { get; }                                            // brand
        public decimal BaseRatePerDay { get; }                                  // base rate

        protected VehicleBase(string reg, string brand, decimal rate)
        {
            Registration = reg;                                                 // assign
            Brand = brand;                                                      // assign
            BaseRatePerDay = rate;                                              // assign
        }

        public abstract decimal CalculateRate(int days);                         // derived pricing
    }

    public sealed class Car : VehicleBase
    {
        public Car(string reg, string brand, decimal rate) : base(reg, brand, rate) { } // base

        // ✅ TODO: Student must implement only this method
        public override decimal CalculateRate(int days)
        {
            // TODO:
            // - Car: total = BaseRatePerDay * days
            // - If days >= 3, apply 5% discount
            throw new NotImplementedException();
        }
    }

    public sealed class Bike : VehicleBase
    {
        public Bike(string reg, string brand, decimal rate) : base(reg, brand, rate) { } // base

        // ✅ TODO: Student must implement only this method
        public override decimal CalculateRate(int days)
        {
            // TODO:
            // - Bike: total = BaseRatePerDay * days
            // - Add fixed safety gear fee: 100 per rental (one-time)
            throw new NotImplementedException();
        }
    }

    public class RentalEngine
    {
        private readonly System.Collections.Generic.Dictionary<string, IVehicle> _vehicles = new(); // inventory

        public void Run(string[] lines)
        {
            foreach (var raw in lines)                                          // each command
            {
                var cmd = Command.Parse(raw);                                   // parse

                if (cmd.Name == "VEHICLE_ADD")                                  // add vehicle
                {
                    var type = cmd.Get("type");                                 // Car/Bike
                    var reg = cmd.Get("reg");                                   // registration
                    var brand = cmd.Get("brand");                               // brand
                    var rate = decimal.Parse(cmd.Get("rate").Replace("₹","").Replace("/day","").Trim()); // parse rate roughly

                    IVehicle v = type.Equals("Car", StringComparison.OrdinalIgnoreCase)
                        ? new Car(reg, brand, rate)
                        : new Bike(reg, brand, rate);                           // create appropriate type

                    _vehicles[reg] = v;                                         // store
                }
                else if (cmd.Name == "RENT")                                    // rent
                {
                    var reg = cmd.Get("reg");                                   // vehicle reg
                    var customer = cmd.Get("customer");                         // customer (may contain #)
                    var days = int.Parse(cmd.Get("days"));                      // days
                    var note = cmd.Get("note");                                 // note

                    var total = CalculateBill(_vehicles[reg], days);            // ✅ TODO pricing
                    Console.WriteLine($"RENT OK | {reg} | {customer} | days={days} | total={total} | note={note}");
                }
            }
        }

        // ✅ TODO: Student must implement only this method
        public decimal CalculateBill(IVehicle vehicle, int days)
        {
            // TODO:
            // - validate days > 0
            // - call vehicle.CalculateRate(days)
            // - return total
            throw new NotImplementedException();
        }
    }

    public class Command
    {
        public string Name { get; }
        private readonly System.Collections.Generic.Dictionary<string, string> _kv;

        private Command(string name, System.Collections.Generic.Dictionary<string, string> kv)
        {
            Name = name; _kv = kv;
        }

        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : "";

        public static Command Parse(string line)
        {
            var parts = line.Split('|');                                        // split
            var name = parts[0].Trim();                                         // name
            var kv = new System.Collections.Generic.Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            for (int i = 1; i < parts.Length; i++)
            {
                var p = parts[i];                                               // token
                var idx = p.IndexOf('=');                                       // '='
                if (idx <= 0) continue;                                         // skip
                var key = p.Substring(0, idx).Trim();                           // key
                var val = p.Substring(idx + 1).Trim().Trim('"');               // value
                kv[key] = val;                                                  // store
            }
            return new Command(name, kv);
        }
    }
}
4

Library Membership: Abstraction + State Validation

OOPAbstractionClass DesignValidationModerate

Scenario: A library system must support borrowing/returning books. Use clear class responsibilities and prevent invalid actions (borrow twice, return without borrow). ✅ Student task: - Implement only TODO methods: 1) Member.Borrow(...) 2) Member.Return(...) 3) Library.AddBook(...) Ask user: - Provide sample input with spaces/special chars in member name and book title.

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console
using System.Collections.Generic; // List, Dictionary, HashSet

namespace ItTechGenie.M1.OOP.Q4
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();                               // read input

            var library = new Library();                                        // create library
            var member = new Member("Sana @ Chennai");                          // create member

            foreach (var raw in lines)                                          // process commands
            {
                var cmd = Command.Parse(raw);                                   // parse

                if (cmd.Name == "LIB_ADD")                                      // add book
                {
                    library.AddBook(new Book(
                        isbn: cmd.Get("isbn"),
                        title: cmd.Get("title"),
                        author: cmd.Get("author"),
                        tag: cmd.Get("tag")
                    ));
                }
                else if (cmd.Name == "BORROW")                                  // borrow
                {
                    member.Borrow(library, cmd.Get("isbn"), cmd.Get("note"));   // ✅ TODO
                }
                else if (cmd.Name == "RETURN")                                  // return
                {
                    member.Return(library, cmd.Get("isbn"));                    // ✅ TODO
                }
            }
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new List<string>();                                      // store lines
            while (true)
            {
                var line = Console.ReadLine();                                  // read
                if (string.IsNullOrWhiteSpace(line)) break;                     // stop
                list.Add(line);                                                 // add
            }
            return list.ToArray();                                              // return
        }
    }

    public record Book(string Isbn, string Title, string Author, string Tag);   // data model

    public class Library
    {
        private readonly Dictionary<string, Book> _books = new();               // isbn -> book
        private readonly HashSet<string> _borrowed = new();                     // borrowed isbns

        // ✅ TODO: Student must implement only this method
        public void AddBook(Book book)
        {
            // TODO:
            // - validate isbn/title/author not empty
            // - ensure isbn unique
            // - store in _books
            throw new NotImplementedException();
        }

        public bool Exists(string isbn) => _books.ContainsKey(isbn);            // check exists
        public Book Get(string isbn) => _books[isbn];                           // get book

        public bool IsBorrowed(string isbn) => _borrowed.Contains(isbn);        // borrowed?
        public void MarkBorrowed(string isbn) => _borrowed.Add(isbn);           // mark
        public void MarkReturned(string isbn) => _borrowed.Remove(isbn);        // unmark
    }

    public class Member
    {
        public string Name { get; }                                             // member name
        private readonly HashSet<string> _myBooks = new();                      // borrowed by this member

        public Member(string name) => Name = name;                              // assign

        // ✅ TODO: Student must implement only this method
        public void Borrow(Library library, string isbn, string note)
        {
            // TODO:
            // - validate library has book
            // - validate not already borrowed in library
            // - validate member hasn't already borrowed
            // - mark borrowed + add to member list
            // - print confirmation using note (note may include !, @, spaces)
            throw new NotImplementedException();
        }

        // ✅ TODO: Student must implement only this method
        public void Return(Library library, string isbn)
        {
            // TODO:
            // - validate member has this book
            // - mark returned in library + remove from member list
            // - print confirmation
            throw new NotImplementedException();
        }
    }

    public class Command
    {
        public string Name { get; }
        private readonly Dictionary<string, string> _kv;

        private Command(string name, Dictionary<string, string> kv)
        {
            Name = name; _kv = kv;
        }

        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : "";

        public static Command Parse(string line)
        {
            var parts = line.Split('|');                                        // split
            var name = parts[0].Trim();                                         // name
            var kv = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            for (int i = 1; i < parts.Length; i++)
            {
                var p = parts[i];
                var idx = p.IndexOf('=');
                if (idx <= 0) continue;
                var key = p.Substring(0, idx).Trim();
                var val = p.Substring(idx + 1).Trim().Trim('"');
                kv[key] = val;
            }
            return new Command(name, kv);
        }
    }
}
5

Order Pricing with Strategy Pattern (OOP Polymorphism)

OOPInterfaceStrategy PatternPolymorphismModerate

Scenario: An order system supports applying different pricing strategies (No coupon, Percentage coupon, Flat coupon). Input contains complex address and coupon codes with special characters. ✅ Student task: - Implement only TODO methods: 1) PricingStrategyFactory.Create(...) 2) PercentageCoupon.Apply(...) 3) FlatCoupon.Apply(...) Ask user: - Provide a sample input with spaces/special chars for address and coupon code.

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console
using System.Collections.Generic; // List

namespace ItTechGenie.M1.OOP.Q5
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();                               // read input

            var engine = new OrderEngine();                                     // create engine
            engine.Run(lines);                                                  // run
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new List<string>();                                      // store lines
            while (true)
            {
                var line = Console.ReadLine();                                  // read
                if (string.IsNullOrWhiteSpace(line)) break;                     // stop
                list.Add(line);                                                 // add
            }
            return list.ToArray();                                              // return
        }
    }

    public class OrderEngine
    {
        private readonly Dictionary<string, Order> _orders = new();             // order store

        public void Run(string[] lines)
        {
            foreach (var raw in lines)                                          // process
            {
                var cmd = Command.Parse(raw);                                   // parse

                if (cmd.Name == "ORDER")                                        // create order
                {
                    var id = cmd.Get("id");                                     // order id
                    var customer = cmd.Get("customer");                         // customer
                    var items = cmd.Get("items");                               // items string
                    var address = cmd.Get("address");                           // address may include commas, quotes, emoji
                    _orders[id] = new Order(id, customer, items, address);      // store
                }
                else if (cmd.Name == "APPLY_COUPON")                             // apply coupon
                {
                    var id = cmd.Get("id");                                     // order id
                    var coupon = cmd.Get("code");                               // coupon code
                    var strategy = PricingStrategyFactory.Create(coupon);       // ✅ TODO factory
                    _orders[id].ApplyPricing(strategy, coupon);                 // apply pricing
                }
                else if (cmd.Name == "PRINT")                                    // print
                {
                    var id = cmd.Get("id");                                     // order id
                    Console.WriteLine(_orders[id].GetSummary());                // print summary
                }
            }
        }
    }

    public class Order
    {
        public string Id { get; }
        public string Customer { get; }
        public string Items { get; }
        public string Address { get; }

        private decimal _subtotal = 15000m;                                     // assume parsed subtotal for demo
        private decimal _total;                                                  // total after coupon

        public Order(string id, string customer, string items, string address)
        {
            Id = id; Customer = customer; Items = items; Address = address;     // assign
            _total = _subtotal;                                                 // initial total
        }

        public void ApplyPricing(IPricingStrategy strategy, string couponCode)
        {
            _total = strategy.Apply(_subtotal, couponCode);                      // polymorphic apply
        }

        public string GetSummary()
        {
            return $"Order[{Id}] Customer={Customer} | Subtotal={_subtotal} | Total={_total} | Address={Address}";
        }
    }

    public interface IPricingStrategy
    {
        decimal Apply(decimal subtotal, string couponCode);                       // apply pricing rule
    }

    public sealed class NoCoupon : IPricingStrategy
    {
        public decimal Apply(decimal subtotal, string couponCode) => subtotal;    // no change
    }

    public sealed class PercentageCoupon : IPricingStrategy
    {
        // ✅ TODO: Student must implement only this method
        public decimal Apply(decimal subtotal, string couponCode)
        {
            // TODO:
            // - read percentage from couponCode like "SAVE@20%#FEB" => 20
            // - apply discount: subtotal * (1 - percent/100)
            throw new NotImplementedException();
        }
    }

    public sealed class FlatCoupon : IPricingStrategy
    {
        // ✅ TODO: Student must implement only this method
        public decimal Apply(decimal subtotal, string couponCode)
        {
            // TODO:
            // - read flat amount from couponCode like "FLAT@500#X" => 500
            // - total cannot go below 0
            throw new NotImplementedException();
        }
    }

    public static class PricingStrategyFactory
    {
        // ✅ TODO: Student must implement only this method
        public static IPricingStrategy Create(string couponCode)
        {
            // TODO:
            // - if couponCode contains '%' => PercentageCoupon
            // - else if contains "FLAT@" => FlatCoupon
            // - else => NoCoupon
            throw new NotImplementedException();
        }
    }

    public class Command
    {
        public string Name { get; }
        private readonly Dictionary<string, string> _kv;

        private Command(string name, Dictionary<string, string> kv) { Name = name; _kv = kv; }
        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : "";

        public static Command Parse(string line)
        {
            var parts = line.Split('|');
            var name = parts[0].Trim();
            var kv = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            for (int i = 1; i < parts.Length; i++)
            {
                var p = parts[i];
                var idx = p.IndexOf('=');
                if (idx <= 0) continue;
                var key = p.Substring(0, idx).Trim();
                var val = p.Substring(idx + 1).Trim().Trim('"');
                kv[key] = val;
            }

            return new Command(name, kv);
        }
    }
}
6

Helpdesk Ticket Workflow using State Pattern

OOPState PatternPolymorphismValidationComplex

Scenario: A helpdesk ticket moves through states: New → InProgress → Resolved. Rules: - New can move only to InProgress - InProgress can move to Resolved - Resolved cannot move further ✅ Student task: - Implement only TODO methods: 1) Ticket.MoveTo(...) 2) StateFactory.FromString(...) 3) ResolvedState.MoveNext(...) (should block) Ask user: - Provide complex inputs (emoji, quotes, symbols) for title/description and actor names.

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console
using System.Collections.Generic; // Dictionary

namespace ItTechGenie.M1.OOP.Q6
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();

            var engine = new TicketEngine();
            engine.Run(lines);
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new List<string>();
            while (true)
            {
                var line = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(line)) break;
                list.Add(line);
            }
            return list.ToArray();
        }
    }

    public class TicketEngine
    {
        private readonly Dictionary<string, Ticket> _tickets = new();

        public void Run(string[] lines)
        {
            foreach (var raw in lines)
            {
                var cmd = Command.Parse(raw);

                if (cmd.Name == "TICKET_NEW")
                {
                    var id = cmd.Get("id");
                    var type = cmd.Get("type");
                    var title = cmd.Get("title");
                    var desc = cmd.Get("desc");
                    _tickets[id] = new Ticket(id, type, title, desc);
                    Console.WriteLine($"Created ticket {id} in state NEW");
                }
                else if (cmd.Name == "MOVE")
                {
                    var id = cmd.Get("id");
                    var to = cmd.Get("to");
                    var by = cmd.Get("by");
                    _tickets[id].MoveTo(to, by);                                // ✅ TODO transitions
                }
            }
        }
    }

    public class Ticket
    {
        public string Id { get; }
        public string Type { get; }
        public string Title { get; }
        public string Description { get; }

        private ITicketState _state = new NewState();                           // initial state

        public Ticket(string id, string type, string title, string description)
        {
            Id = id; Type = type; Title = title; Description = description;     // assign
        }

        // ✅ TODO: Student must implement only this method
        public void MoveTo(string nextStateName, string actor)
        {
            // TODO:
            // - Convert nextStateName into ITicketState using StateFactory.FromString
            // - Ask current state to validate transition
            // - If allowed, switch _state and print transition line
            throw new NotImplementedException();
        }
    }

    public interface ITicketState
    {
        string Name { get; }                                                    // state name
        void MoveNext(ITicketState next);                                       // validate transition
    }

    public sealed class NewState : ITicketState
    {
        public string Name => "New";
        public void MoveNext(ITicketState next)
        {
            if (next is not InProgressState) throw new InvalidOperationException("New -> only InProgress allowed");
        }
    }

    public sealed class InProgressState : ITicketState
    {
        public string Name => "InProgress";
        public void MoveNext(ITicketState next)
        {
            if (next is not ResolvedState) throw new InvalidOperationException("InProgress -> only Resolved allowed");
        }
    }

    public sealed class ResolvedState : ITicketState
    {
        public string Name => "Resolved";

        // ✅ TODO: Student must implement only this method
        public void MoveNext(ITicketState next)
        {
            // TODO:
            // - Resolved should NOT allow any transition
            // - throw InvalidOperationException with clear message
            throw new NotImplementedException();
        }
    }

    public static class StateFactory
    {
        // ✅ TODO: Student must implement only this method
        public static ITicketState FromString(string stateName)
        {
            // TODO:
            // - accept "New", "InProgress", "Resolved" (case-insensitive)
            // - return correct state object
            // - throw for unknown state
            throw new NotImplementedException();
        }
    }

    public class Command
    {
        public string Name { get; }
        private readonly Dictionary<string, string> _kv;

        private Command(string name, Dictionary<string, string> kv){ Name = name; _kv = kv; }
        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : "";

        public static Command Parse(string line)
        {
            var parts = line.Split('|');
            var name = parts[0].Trim();
            var kv = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            for (int i = 1; i < parts.Length; i++)
            {
                var p = parts[i];
                var idx = p.IndexOf('=');
                if (idx <= 0) continue;
                var key = p.Substring(0, idx).Trim();
                var val = p.Substring(idx + 1).Trim().Trim('"');
                kv[key] = val;
            }
            return new Command(name, kv);
        }
    }
}
7

Payment Gateway using Factory + Strategy + Exceptions

OOPFactory PatternStrategy PatternExceptionsComplex

Scenario: Your checkout supports multiple payment methods (Card, Wallet) and refunds. Each method has different validation rules, and failures must be handled cleanly. ✅ Student task: - Implement only TODO methods: 1) PaymentProcessor.Process(...) 2) PaymentMethodFactory.Create(...) 3) CardPayment.Validate(...) Ask user: - Provide complex input metadata (masked card, spaces, OTP with spaces, special symbols).

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console
using System.Collections.Generic; // Dictionary, List

namespace ItTechGenie.M1.OOP.Q7
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();

            var processor = new PaymentProcessor();
            processor.Run(lines);
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new List<string>();
            while (true)
            {
                var line = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(line)) break;
                list.Add(line);
            }
            return list.ToArray();
        }
    }

    public class PaymentProcessor
    {
        // store processed payments for audit (simple demo)
        private readonly List<string> _audit = new();

        public void Run(string[] lines)
        {
            foreach (var raw in lines)
            {
                var cmd = Command.Parse(raw);

                if (cmd.Name == "PAYMENT")
                {
                    Process(cmd);                                               // ✅ TODO core
                }
                else if (cmd.Name == "REFUND")
                {
                    var order = cmd.Get("order");
                    var amount = Amount.Parse(cmd.Get("amount"));
                    Console.WriteLine($"REFUND OK | order={order} | amount={amount}");
                }
            }
        }

        // ✅ TODO: Student must implement only this method
        public void Process(Command cmd)
        {
            // TODO:
            // - parse order, method, amount, meta
            // - create payment method via PaymentMethodFactory.Create(method)
            // - validate using method.Validate(meta)
            // - print success and add audit record
            // - on validation failure, print "PAYMENT FAILED" with reason (do not crash)
            throw new NotImplementedException();
        }
    }

    public interface IPaymentMethod
    {
        string Name { get; }                                                    // method name
        void Validate(string meta);                                             // validate metadata string
    }

    public sealed class CardPayment : IPaymentMethod
    {
        public string Name => "Card";

        // ✅ TODO: Student must implement only this method
        public void Validate(string meta)
        {
            // TODO:
            // - meta example: "**** 4242|VISA|OTP=12 34"
            // - ensure last4 exists and OTP has at least 4 digits total (spaces allowed)
            // - throw ArgumentException if invalid
            throw new NotImplementedException();
        }
    }

    public sealed class WalletPayment : IPaymentMethod
    {
        public string Name => "Wallet";
        public void Validate(string meta)
        {
            if (string.IsNullOrWhiteSpace(meta)) throw new ArgumentException("Wallet meta required");
        }
    }

    public static class PaymentMethodFactory
    {
        // ✅ TODO: Student must implement only this method
        public static IPaymentMethod Create(string method)
        {
            // TODO:
            // - support "Card" and "Wallet" (case-insensitive)
            // - return correct object
            // - throw for unknown method
            throw new NotImplementedException();
        }
    }

    public static class Amount
    {
        public static decimal Parse(string raw)
        {
            // Keep parse simple: strip ₹ and commas (students can enhance)
            raw = raw.Replace("₹", "").Replace(",", "").Trim();
            return decimal.Parse(raw);
        }
    }

    public class Command
    {
        public string Name { get; }
        private readonly Dictionary<string, string> _kv;

        private Command(string name, Dictionary<string, string> kv){ Name = name; _kv = kv; }
        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : "";

        public static Command Parse(string line)
        {
            var parts = line.Split('|');
            var name = parts[0].Trim();
            var kv = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            for (int i = 1; i < parts.Length; i++)
            {
                var p = parts[i];
                var idx = p.IndexOf('=');
                if (idx <= 0) continue;
                var key = p.Substring(0, idx).Trim();
                var val = p.Substring(idx + 1).Trim().Trim('"');
                kv[key] = val;
            }
            return new Command(name, kv);
        }
    }
}
8

Shipment Tracking using Events + Composition

OOPEventsCompositionEncapsulationComplex

Scenario: A logistics service tracks shipment events (PickedUp, InTransit, Delivered). When Delivered happens, raise an event to notify subscribers. ✅ Student task: - Implement only TODO methods: 1) Shipment.AddEvent(...) 2) ShipmentFactory.CreateFromInput(...) 3) Delivered event invocation Ask user: - Provide input with quotes, spaces in address and agent names, and special chars.

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console
using System.Collections.Generic; // List, Dictionary

namespace ItTechGenie.M1.OOP.Q8
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();

            var shipment = ShipmentFactory.CreateFromInput(lines);              // ✅ TODO build shipment from input

            shipment.Delivered += s => Console.WriteLine($"✅ Delivered event: {s.Id} to {s.Address}"); // subscribe
            shipment.PrintTimeline();                                           // print all events
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new List<string>();
            while (true)
            {
                var line = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(line)) break;
                list.Add(line);
            }
            return list.ToArray();
        }
    }

    public class Shipment
    {
        public string Id { get; }                                               // shipment id
        public string Mode { get; }                                             // mode
        public string Address { get; }                                          // address

        private readonly List<ShipmentEvent> _events = new();                   // timeline
        public event Action<Shipment>? Delivered;                               // event when delivered

        public Shipment(string id, string mode, string address)
        {
            Id = id; Mode = mode; Address = address;                            // assign
        }

        // ✅ TODO: Student must implement only this method
        public void AddEvent(ShipmentEvent ev)
        {
            // TODO:
            // - add to _events
            // - if ev.Type == "Delivered" => invoke Delivered event safely
            throw new NotImplementedException();
        }

        public void PrintTimeline()
        {
            Console.WriteLine($"Shipment[{Id}] Mode={Mode} Address={Address}");
            foreach (var e in _events) Console.WriteLine($"{e.Type} | {e.Time} | {e.By}");
        }
    }

    public record ShipmentEvent(string Type, string Time, string By);           // event model

    public static class ShipmentFactory
    {
        // ✅ TODO: Student must implement only this method
        public static Shipment CreateFromInput(string[] lines)
        {
            // TODO:
            // - parse SHIPMENT line first (id, mode, address)
            // - then parse EVENT lines and add to shipment using shipment.AddEvent(...)
            // - return the shipment
            throw new NotImplementedException();
        }
    }

    public class Command
    {
        public string Name { get; }
        private readonly Dictionary<string, string> _kv;

        private Command(string name, Dictionary<string, string> kv){ Name = name; _kv = kv; }
        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : "";

        public static Command Parse(string line)
        {
            var parts = line.Split('|');
            var name = parts[0].Trim();
            var kv = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            for (int i = 1; i < parts.Length; i++)
            {
                var p = parts[i];
                var idx = p.IndexOf('=');
                if (idx <= 0) continue;
                var key = p.Substring(0, idx).Trim();
                var val = p.Substring(idx + 1).Trim().Trim('"');
                kv[key] = val;
            }
            return new Command(name, kv);
        }
    }
}
9

Inventory + Discount Rules using Decorator-like Composition

OOPCompositionInterfaceOpen/ClosedComplex

Scenario: Inventory holds products. Discounts are applied by wrapping a product with a discount rule (composition). Input includes unicode SKU, spaces, punctuation, and emoji. ✅ Student task: - Implement only TODO methods: 1) Inventory.AddProduct(...) 2) DiscountRule.Apply(...) 3) ReportPrinter.PrintCsv(...) Ask user: - Provide sample input containing spaces, unicode characters (α, β), and punctuation.

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console
using System.Collections.Generic; // Dictionary, List

namespace ItTechGenie.M1.OOP.Q9
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();

            var inventory = new Inventory();                                    // create inventory

            foreach (var raw in lines)
            {
                var cmd = Command.Parse(raw);

                if (cmd.Name == "INVENTORY")
                {
                    inventory.AddProduct(new Product(                           // ✅ TODO add
                        sku: cmd.Get("sku"),
                        name: cmd.Get("name"),
                        qty: int.Parse(cmd.Get("qty")),
                        price: Amount.Parse(cmd.Get("price"))
                    ));
                }
                else if (cmd.Name == "DISCOUNT")
                {
                    inventory.ApplyDiscount(cmd.Get("sku"),
                        new DiscountRule(percent: decimal.Parse(cmd.Get("percent")), reason: cmd.Get("reason")));
                }
                else if (cmd.Name == "REPORT")
                {
                    ReportPrinter.PrintCsv(inventory.GetAll(), cmd.Get("delim")); // ✅ TODO printer
                }
            }
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new List<string>();
            while (true)
            {
                var line = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(line)) break;
                list.Add(line);
            }
            return list.ToArray();
        }
    }

    public interface IProductView
    {
        string Sku { get; }                                                     // sku
        string Name { get; }                                                    // name
        int Qty { get; }                                                        // quantity
        decimal UnitPrice { get; }                                              // final unit price
    }

    public class Product : IProductView
    {
        public string Sku { get; }
        public string Name { get; }
        public int Qty { get; }
        public decimal UnitPrice { get; }                                       // base unit price

        public Product(string sku, string name, int qty, decimal price)
        {
            Sku = sku; Name = name; Qty = qty; UnitPrice = price;
        }
    }

    public class DiscountedProduct : IProductView
    {
        private readonly IProductView _inner;                                   // wrapped product
        private readonly DiscountRule _rule;                                    // rule

        public DiscountedProduct(IProductView inner, DiscountRule rule)
        {
            _inner = inner; _rule = rule;
        }

        public string Sku => _inner.Sku;
        public string Name => _inner.Name;
        public int Qty => _inner.Qty;
        public decimal UnitPrice => _rule.Apply(_inner.UnitPrice);              // ✅ TODO apply rule
    }

    public class DiscountRule
    {
        public decimal Percent { get; }                                         // percent
        public string Reason { get; }                                           // reason text

        public DiscountRule(decimal percent, string reason)
        {
            Percent = percent; Reason = reason;
        }

        // ✅ TODO: Student must implement only this method
        public decimal Apply(decimal basePrice)
        {
            // TODO:
            // - validate Percent between 0 and 100
            // - return discounted price
            throw new NotImplementedException();
        }
    }

    public class Inventory
    {
        private readonly Dictionary<string, IProductView> _store = new();       // sku -> product view

        // ✅ TODO: Student must implement only this method
        public void AddProduct(Product p)
        {
            // TODO:
            // - validate sku/name not empty (may contain unicode like α, β)
            // - validate qty >= 0 and price >= 0
            // - ensure sku unique
            throw new NotImplementedException();
        }

        public void ApplyDiscount(string sku, DiscountRule rule)
        {
            if (!_store.ContainsKey(sku)) return;
            _store[sku] = new DiscountedProduct(_store[sku], rule);             // wrap product (composition)
        }

        public IEnumerable<IProductView> GetAll() => _store.Values;             // return all
    }

    public static class ReportPrinter
    {
        // ✅ TODO: Student must implement only this method
        public static void PrintCsv(IEnumerable<IProductView> products, string delim)
        {
            // TODO:
            // - default delimiter ';' if empty
            // - print header and rows safely (escape delimiter if found in name)
            throw new NotImplementedException();
        }
    }

    public static class Amount
    {
        public static decimal Parse(string raw)
        {
            raw = raw.Replace("₹", "").Replace(",", "").Trim();
            return decimal.Parse(raw);
        }
    }

    public class Command
    {
        public string Name { get; }
        private readonly Dictionary<string, string> _kv;

        private Command(string name, Dictionary<string, string> kv){ Name = name; _kv = kv; }
        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : "";

        public static Command Parse(string line)
        {
            var parts = line.Split('|');
            var name = parts[0].Trim();
            var kv = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            for (int i = 1; i < parts.Length; i++)
            {
                var p = parts[i];
                var idx = p.IndexOf('=');
                if (idx <= 0) continue;
                var key = p.Substring(0, idx).Trim();
                var val = p.Substring(idx + 1).Trim().Trim('"');
                kv[key] = val;
            }
            return new Command(name, kv);
        }
    }
}
10

Workflow Engine using Command Pattern + Polymorphism

OOPCommand PatternPolymorphismExtensibilityComplex

Scenario: A workflow contains steps: Email, Task, Approval. Each step runs differently. Use OOP polymorphism so new steps can be added without changing core engine. ✅ Student task: - Implement only TODO methods: 1) WorkflowEngine.ParseStep(...) 2) EmailStep.Execute(...) 3) ApprovalStep.Execute(...) Ask user: - Provide complex input including quotes, commas, special chars in body/title/approver name.

✅ Input examples above include: spaces, quotes, ₹ symbol, commas, emoji, unicode (α/β), and special chars like @ # % !. Replace with your own test data if needed.
Boilerplate C# console program (students implement ONLY TODO methods) Ctrl+C
using System; // Console
using System.Collections.Generic; // List

namespace ItTechGenie.M1.OOP.Q10
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Paste input lines, end with EMPTY line:");
            var lines = ConsoleInput.ReadLines();

            var engine = new WorkflowEngine();
            engine.Run(lines);
        }
    }

    public static class ConsoleInput
    {
        public static string[] ReadLines()
        {
            var list = new List<string>();
            while (true)
            {
                var line = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(line)) break;
                list.Add(line);
            }
            return list.ToArray();
        }
    }

    public class WorkflowEngine
    {
        public void Run(string[] lines)
        {
            Workflow? wf = null;                                                // current workflow

            foreach (var raw in lines)
            {
                var cmd = Command.Parse(raw);

                if (cmd.Name == "WORKFLOW")
                {
                    wf = new Workflow(cmd.Get("id"), cmd.Get("name"));          // create workflow
                }
                else if (cmd.Name == "STEP" && wf != null)
                {
                    wf.AddStep(ParseStep(cmd));                                 // ✅ TODO parse step
                }
                else if (cmd.Name == "RUN" && wf != null)
                {
                    wf.ExecuteAll(dryRun: cmd.Get("dryRun").Equals("true", StringComparison.OrdinalIgnoreCase)); // run
                }
            }
        }

        // ✅ TODO: Student must implement only this method
        public IWorkflowStep ParseStep(Command cmd)
        {
            // TODO:
            // - read cmd.Get("type") => Email / Task / Approval
            // - create appropriate step object with required fields
            // - throw for unknown type
            throw new NotImplementedException();
        }
    }

    public class Workflow
    {
        public string Id { get; }
        public string Name { get; }

        private readonly List<IWorkflowStep> _steps = new();                    // steps list

        public Workflow(string id, string name){ Id = id; Name = name; }

        public void AddStep(IWorkflowStep step) => _steps.Add(step);            // add

        public void ExecuteAll(bool dryRun)
        {
            Console.WriteLine($"Workflow[{Id}] {Name} | dryRun={dryRun}");
            foreach (var s in _steps) s.Execute(dryRun);                         // polymorphic execute
        }
    }

    public interface IWorkflowStep
    {
        void Execute(bool dryRun);                                              // execute step
    }

    public sealed class EmailStep : IWorkflowStep
    {
        public string To { get; }
        public string Body { get; }

        public EmailStep(string to, string body){ To = to; Body = body; }

        // ✅ TODO: Student must implement only this method
        public void Execute(bool dryRun)
        {
            // TODO:
            // - if dryRun => print "DRYRUN Email to ..."
            // - else => print "SENT Email to ..." (simulate)
            throw new NotImplementedException();
        }
    }

    public sealed class TaskStep : IWorkflowStep
    {
        public string Assignee { get; }
        public string Title { get; }

        public TaskStep(string assignee, string title){ Assignee = assignee; Title = title; }

        public void Execute(bool dryRun)
        {
            var prefix = dryRun ? "DRYRUN" : "CREATED";
            Console.WriteLine($"{prefix} Task for {Assignee} | {Title}");
        }
    }

    public sealed class ApprovalStep : IWorkflowStep
    {
        public string Approver { get; }
        public string Note { get; }

        public ApprovalStep(string approver, string note){ Approver = approver; Note = note; }

        // ✅ TODO: Student must implement only this method
        public void Execute(bool dryRun)
        {
            // TODO:
            // - if dryRun => print "DRYRUN Approval request to ..."
            // - else => print "SENT Approval request to ..." (simulate)
            throw new NotImplementedException();
        }
    }

    public class Command
    {
        public string Name { get; }
        private readonly Dictionary<string, string> _kv;

        private Command(string name, Dictionary<string, string> kv){ Name = name; _kv = kv; }
        public string Get(string key) => _kv.TryGetValue(key, out var v) ? v : "";

        public static Command Parse(string line)
        {
            var parts = line.Split('|');
            var name = parts[0].Trim();
            var kv = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            for (int i = 1; i < parts.Length; i++)
            {
                var p = parts[i];
                var idx = p.IndexOf('=');
                if (idx <= 0) continue;
                var key = p.Substring(0, idx).Trim();
                var val = p.Substring(idx + 1).Trim().Trim('"');
                kv[key] = val;
            }

            return new Command(name, kv);
        }
    }
}