C# Advanced - Topic-wise Practice

15 hard problems. Predict output, spot bugs, write code. No multiple choice.

Rules: Try before expanding solutions. Type the code. Don't just read. Kunal learns by breaking things.

1. Delegates & Events - 3 Problems

P1. Predict Output: What prints?

Action a = null;
a += () => Console.Write("A");
a += () => Console.Write("B");
a -= () => Console.Write("A");
a?.Invoke();
Show Solution
Output: AB
Why: -= only removes if delegate instance matches. Lambdas create new instances. The -= did nothing. Both A and B remain. Use named methods to remove: a -= MyMethod;

P2. Spot the Bug: Memory leak. Find it.

class Window {
    public Window(Button btn) {
        btn.Click += () => this.Close(); // Prerna's code
    }
}
Show Solution
Bug: Lambda captures this. Button now holds ref to Window. If Button lives longer than Window, Window never GC'd.
Fix: Unsubscribe in Dispose, or use named method + -=, or WeakEventManager.

P3. Write Code: Create SafeEvent<T> that won't throw if null and catches subscriber exceptions.

Show Solution
public class SafeEvent<T> {
    private event Action<T> _handlers;
    public void Subscribe(Action<T> handler) => _handlers += handler;
    public void Unsubscribe(Action<T> handler) => _handlers -= handler;
    
    public void Raise(T args) {
        var handlers = _handlers; // Thread-safe copy
        if (handlers == null) return;
        foreach (Action<T> handler in handlers.GetInvocationList()) {
            try { handler(args); }
            catch (Exception ex) { Console.WriteLine($"Handler failed: {ex}"); }
        }
    }
}

2. LINQ - 3 Problems

P4. Predict Output: How many times does "Check" print?

var nums = new List<int> {1,2,3};
var q = nums.Where(n => { Console.WriteLine("Check"); return n > 1; });
Console.WriteLine(q.Count());
Console.WriteLine(q.Count());
Show Solution
Output: Check prints 6 times. Then 3, then 3.
Why: Deferred execution. q.Count() enumerates q each time. 3 items ร— 2 calls = 6 checks. Fix: var list = q.ToList(); materialize once.

P5. Spot the Bug: This is slow. Why?

var result = db.Users
   .Where(u => u.IsActive)
   .ToList()
   .Where(u => u.Orders.Any(o => o.Total > 100)) // Kaushal's filter
   .ToList();
Show Solution
Bug: First ToList() loads ALL active users to memory. Then filters in C#, not SQL. If 1M users, you pull 1M rows.
Fix: Remove first ToList(). Let EF translate whole query to SQL: db.Users.Where(u => u.IsActive && u.Orders.Any(...)).ToList()

P6. Write Code: Given List<string> names, return dictionary of first-letter โ†’ count, using LINQ.

Show Solution
var counts = names
   .GroupBy(n => n[0])
   .ToDictionary(g => g.Key, g => g.Count());
    
// Result: { 'K': 3, 'P': 2 } for ["Kunal", "Kaushal", "Karan", "Prerna", "Prerna"]

3. Async & Await - 3 Problems

P7. Predict Output: Order?

async Task Test() {
    Console.Write("A");
    await Task.Delay(1);
    Console.Write("B");
}
Console.Write("C");
Test();
Console.Write("D");
Show Solution
Output: CADB
Why: C prints. Test() prints A, hits await, returns to caller. D prints. Later B prints when Delay completes.

P8. Spot the Bug: Sanju's API is slow. Why?

public async Task<User> GetUser(int id) {
    var user = await db.Users.FindAsync(id);
    var orders = await db.Orders.Where(o => o.UserId == id).ToListAsync();
    var posts = await db.Posts.Where(p => p.UserId == id).ToListAsync();
    return user;
}
Show Solution
Bug: Sequential awaits. 3 DB calls run one after another. 100ms + 100ms + 100ms = 300ms.
Fix: Start all, then await all: var t1 = db.Users.FindAsync(id); var t2 =...; await Task.WhenAll(t1,t2,t3); Now ~100ms total.

P9. Write Code: Implement Task.Delay using TaskCompletionSource.

Show Solution
public static Task Delay(int ms) {
    var tcs = new TaskCompletionSource<bool>();
    var timer = new System.Timers.Timer(ms) { AutoReset = false };
    timer.Elapsed += (s, e) => { tcs.SetResult(true); timer.Dispose(); };
    timer.Start();
    return tcs.Task;
}

4. Generics - 3 Problems

P10. Predict Output: What prints?

void Print<T>(T item) => Console.Write(typeof(T).Name);
Print(5);
Print("hi");
Show Solution
Output: Int32String
Why: Compiler infers T from argument. T = int, then T = string. typeof(T).Name gives type name.

P11. Spot the Bug: Why won't this compile?

class Cache<T> {
    T value;
    public bool IsNull() => value == null; // Karan's code
}
Show Solution
Bug: If T is int, value == null is invalid. int can't be null.
Fix: where T : class constraint, or use EqualityComparer<T>.Default.Equals(value, default(T))

P12. Write Code: Generic Swap<T>(ref T a, ref T b)

Show Solution
public static void Swap<T>(ref T a, ref T b) {
    T temp = a;
    a = b;
    b = temp;
}
// Usage: int x=1,y=2; Swap(ref x, ref y);

5. File I/O - 3 Problems

P13. Predict Output: File has "AB\nCD". What prints?

using var r = new StreamReader("f.txt");
Console.Write(r.ReadLine());
Console.Write(r.ReadToEnd());
Show Solution
Output: ABCD
Why: ReadLine() reads "AB" and consumes \n. ReadToEnd() reads "CD". No newline printed between.

P14. Spot the Bug: "File in use" error. Why?

var w = new StreamWriter("log.txt");
w.WriteLine("Start");
//... crash here
w.WriteLine("End"); // Kashvee never reaches this
Show Solution
Bug: No using or Dispose(). If exception occurs, file handle never released. File stays locked.
Fix: using var w = new StreamWriter("log.txt"); Dispose called even on exception.

P15. Write Code: Async method to count lines in 10GB file without loading to RAM.

Show Solution
public static async Task<long> CountLinesAsync(string path) {
    long count = 0;
    using var reader = new StreamReader(path);
    while (await reader.ReadLineAsync()!= null) {
        count++;
    }
    return count;
} // Memory: 4KB buffer. Works for any file size.
Done? If you solved 12/15 without peeking, you're job-ready.

Comments on Advanced - Topic-wise Practice (0)

No comments yet. Be the first to share your thoughts!