0% found this document useful (0 votes)
13 views101 pages

200 Practical CSharp Coding QA Detailed

The document contains a series of practical C# coding questions and answers covering various topics such as OOP, structs, generics, LINQ, async/await, delegates, collections, exception handling, and threading. Each question provides detailed explanations, examples, and best practices for using specific C# features effectively. The content is aimed at enhancing understanding and application of C# programming concepts in real-world scenarios.

Uploaded by

vinshet116
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views101 pages

200 Practical CSharp Coding QA Detailed

The document contains a series of practical C# coding questions and answers covering various topics such as OOP, structs, generics, LINQ, async/await, delegates, collections, exception handling, and threading. Each question provides detailed explanations, examples, and best practices for using specific C# features effectively. The content is aimed at enhancing understanding and application of C# programming concepts in real-world scenarios.

Uploaded by

vinshet116
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

200 Practical C# Coding Questions & Answers

(Detailed Explanations)

Q1. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an interface
in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #1: This question relates to practical scenario #1 and includes variant considerations such as
performance, memory, and maintainability.

Q2. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a sample
struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #2: This question relates to practical scenario #2 and includes variant considerations such as
performance, memory, and maintainability.

Q3. (Generics) Explain covariance and contravariance with generics in C# and give code examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #3: This question relates to practical scenario #3 and includes variant considerations such as
performance, memory, and maintainability.

Q4. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #4: This question relates to practical scenario #4 and includes variant considerations such as
performance, memory, and maintainability.

Q5. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #5: This question relates to practical scenario #5 and includes variant considerations such as
performance, memory, and maintainability.
Q6. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #6: This question relates to practical scenario #6 and includes variant considerations such as
performance, memory, and maintainability.

Q7. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #7: This question relates to practical scenario #7 and includes variant considerations such as
performance, memory, and maintainability.
Q8. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #8: This question relates to practical scenario #8 and includes variant considerations such as
performance, memory, and maintainability.

Q9. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`, `SemaphoreSlim`,
and when to use each. Provide a sample using `SemaphoreSlim` for limiting concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #9: This question relates to practical scenario #9 and includes variant considerations such as
performance, memory, and maintainability.

Q10. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #10: This question relates to practical scenario #10 and includes variant considerations such as
performance, memory, and maintainability.

Q11. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #11: This question relates to practical scenario #11 and includes variant considerations such as
performance, memory, and maintainability.
Q12. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #12: This question relates to practical scenario #12 and includes variant considerations such as
performance, memory, and maintainability.

Q13. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #13: This question relates to practical scenario #13 and includes variant considerations such as
performance, memory, and maintainability.
Q14. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #14: This question relates to practical scenario #14 and includes variant considerations such as
performance, memory, and maintainability.

Q15. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #15: This question relates to practical scenario #15 and includes variant considerations such as
performance, memory, and maintainability.

Q16. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #16: This question relates to practical scenario #16 and includes variant considerations such as
performance, memory, and maintainability.

Q17. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #17: This question relates to practical scenario #17 and includes variant considerations such as
performance, memory, and maintainability.

Q18. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #18: This question relates to practical scenario #18 and includes variant considerations such as
performance, memory, and maintainability.

Q19. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #19: This question relates to practical scenario #19 and includes variant considerations such as
performance, memory, and maintainability.

Q20. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #20: This question relates to practical scenario #20 and includes variant considerations such as
performance, memory, and maintainability.

Q21. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #21: This question relates to practical scenario #21 and includes variant considerations such as
performance, memory, and maintainability.
Q22. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #22: This question relates to practical scenario #22 and includes variant considerations such as
performance, memory, and maintainability.

Q23. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #23: This question relates to practical scenario #23 and includes variant considerations such as
performance, memory, and maintainability.

Q24. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #24: This question relates to practical scenario #24 and includes variant considerations such as
performance, memory, and maintainability.

Q25. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #25: This question relates to practical scenario #25 and includes variant considerations such as
performance, memory, and maintainability.

Q26. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #26: This question relates to practical scenario #26 and includes variant considerations such as
performance, memory, and maintainability.

Q27. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #27: This question relates to practical scenario #27 and includes variant considerations such as
performance, memory, and maintainability.

Q28. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #28: This question relates to practical scenario #28 and includes variant considerations such as
performance, memory, and maintainability.

Q29. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #29: This question relates to practical scenario #29 and includes variant considerations such as
performance, memory, and maintainability.
Q30. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #30: This question relates to practical scenario #30 and includes variant considerations such as
performance, memory, and maintainability.

Q31. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #31: This question relates to practical scenario #31 and includes variant considerations such as
performance, memory, and maintainability.
Q32. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #32: This question relates to practical scenario #32 and includes variant considerations such as
performance, memory, and maintainability.

Q33. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #33: This question relates to practical scenario #33 and includes variant considerations such as
performance, memory, and maintainability.

Q34. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #34: This question relates to practical scenario #34 and includes variant considerations such as
performance, memory, and maintainability.

Q35. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #35: This question relates to practical scenario #35 and includes variant considerations such as
performance, memory, and maintainability.

Q36. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #36: This question relates to practical scenario #36 and includes variant considerations such as
performance, memory, and maintainability.

Q37. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #37: This question relates to practical scenario #37 and includes variant considerations such as
performance, memory, and maintainability.

Q38. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #38: This question relates to practical scenario #38 and includes variant considerations such as
performance, memory, and maintainability.

Q39. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #39: This question relates to practical scenario #39 and includes variant considerations such as
performance, memory, and maintainability.
Q40. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #40: This question relates to practical scenario #40 and includes variant considerations such as
performance, memory, and maintainability.

Q41. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #41: This question relates to practical scenario #41 and includes variant considerations such as
performance, memory, and maintainability.

Q42. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #42: This question relates to practical scenario #42 and includes variant considerations such as
performance, memory, and maintainability.

Q43. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #43: This question relates to practical scenario #43 and includes variant considerations such as
performance, memory, and maintainability.

Q44. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #44: This question relates to practical scenario #44 and includes variant considerations such as
performance, memory, and maintainability.

Q45. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #45: This question relates to practical scenario #45 and includes variant considerations such as
performance, memory, and maintainability.

Q46. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #46: This question relates to practical scenario #46 and includes variant considerations such as
performance, memory, and maintainability.

Q47. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #47: This question relates to practical scenario #47 and includes variant considerations such as
performance, memory, and maintainability.
Q48. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #48: This question relates to practical scenario #48 and includes variant considerations such as
performance, memory, and maintainability.

Q49. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #49: This question relates to practical scenario #49 and includes variant considerations such as
performance, memory, and maintainability.
Q50. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #50: This question relates to practical scenario #50 and includes variant considerations such as
performance, memory, and maintainability.

Q51. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #51: This question relates to practical scenario #51 and includes variant considerations such as
performance, memory, and maintainability.

Q52. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #52: This question relates to practical scenario #52 and includes variant considerations such as
performance, memory, and maintainability.

Q53. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #53: This question relates to practical scenario #53 and includes variant considerations such as
performance, memory, and maintainability.

Q54. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #54: This question relates to practical scenario #54 and includes variant considerations such as
performance, memory, and maintainability.

Q55. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #55: This question relates to practical scenario #55 and includes variant considerations such as
performance, memory, and maintainability.

Q56. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #56: This question relates to practical scenario #56 and includes variant considerations such as
performance, memory, and maintainability.

Q57. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #57: This question relates to practical scenario #57 and includes variant considerations such as
performance, memory, and maintainability.
Q58. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #58: This question relates to practical scenario #58 and includes variant considerations such as
performance, memory, and maintainability.

Q59. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #59: This question relates to practical scenario #59 and includes variant considerations such as
performance, memory, and maintainability.

Q60. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #60: This question relates to practical scenario #60 and includes variant considerations such as
performance, memory, and maintainability.

Q61. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #61: This question relates to practical scenario #61 and includes variant considerations such as
performance, memory, and maintainability.

Q62. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #62: This question relates to practical scenario #62 and includes variant considerations such as
performance, memory, and maintainability.

Q63. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #63: This question relates to practical scenario #63 and includes variant considerations such as
performance, memory, and maintainability.

Q64. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #64: This question relates to practical scenario #64 and includes variant considerations such as
performance, memory, and maintainability.

Q65. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #65: This question relates to practical scenario #65 and includes variant considerations such as
performance, memory, and maintainability.
Q66. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #66: This question relates to practical scenario #66 and includes variant considerations such as
performance, memory, and maintainability.

Q67. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #67: This question relates to practical scenario #67 and includes variant considerations such as
performance, memory, and maintainability.
Q68. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #68: This question relates to practical scenario #68 and includes variant considerations such as
performance, memory, and maintainability.

Q69. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #69: This question relates to practical scenario #69 and includes variant considerations such as
performance, memory, and maintainability.

Q70. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #70: This question relates to practical scenario #70 and includes variant considerations such as
performance, memory, and maintainability.

Q71. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #71: This question relates to practical scenario #71 and includes variant considerations such as
performance, memory, and maintainability.

Q72. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #72: This question relates to practical scenario #72 and includes variant considerations such as
performance, memory, and maintainability.

Q73. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #73: This question relates to practical scenario #73 and includes variant considerations such as
performance, memory, and maintainability.

Q74. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #74: This question relates to practical scenario #74 and includes variant considerations such as
performance, memory, and maintainability.

Q75. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #75: This question relates to practical scenario #75 and includes variant considerations such as
performance, memory, and maintainability.
Q76. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #76: This question relates to practical scenario #76 and includes variant considerations such as
performance, memory, and maintainability.

Q77. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #77: This question relates to practical scenario #77 and includes variant considerations such as
performance, memory, and maintainability.

Q78. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #78: This question relates to practical scenario #78 and includes variant considerations such as
performance, memory, and maintainability.

Q79. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #79: This question relates to practical scenario #79 and includes variant considerations such as
performance, memory, and maintainability.

Q80. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #80: This question relates to practical scenario #80 and includes variant considerations such as
performance, memory, and maintainability.

Q81. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #81: This question relates to practical scenario #81 and includes variant considerations such as
performance, memory, and maintainability.

Q82. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #82: This question relates to practical scenario #82 and includes variant considerations such as
performance, memory, and maintainability.

Q83. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #83: This question relates to practical scenario #83 and includes variant considerations such as
performance, memory, and maintainability.
Q84. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #84: This question relates to practical scenario #84 and includes variant considerations such as
performance, memory, and maintainability.

Q85. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #85: This question relates to practical scenario #85 and includes variant considerations such as
performance, memory, and maintainability.
Q86. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #86: This question relates to practical scenario #86 and includes variant considerations such as
performance, memory, and maintainability.

Q87. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #87: This question relates to practical scenario #87 and includes variant considerations such as
performance, memory, and maintainability.

Q88. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #88: This question relates to practical scenario #88 and includes variant considerations such as
performance, memory, and maintainability.

Q89. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #89: This question relates to practical scenario #89 and includes variant considerations such as
performance, memory, and maintainability.

Q90. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #90: This question relates to practical scenario #90 and includes variant considerations such as
performance, memory, and maintainability.

Q91. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #91: This question relates to practical scenario #91 and includes variant considerations such as
performance, memory, and maintainability.

Q92. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #92: This question relates to practical scenario #92 and includes variant considerations such as
performance, memory, and maintainability.

Q93. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #93: This question relates to practical scenario #93 and includes variant considerations such as
performance, memory, and maintainability.
Q94. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #94: This question relates to practical scenario #94 and includes variant considerations such as
performance, memory, and maintainability.

Q95. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #95: This question relates to practical scenario #95 and includes variant considerations such as
performance, memory, and maintainability.

Q96. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #96: This question relates to practical scenario #96 and includes variant considerations such as
performance, memory, and maintainability.

Q97. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #97: This question relates to practical scenario #97 and includes variant considerations such as
performance, memory, and maintainability.

Q98. (Exception Handling) Best practices for exception handling in C# and how to create a custom
exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #98: This question relates to practical scenario #98 and includes variant considerations such as
performance, memory, and maintainability.

Q99. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #99: This question relates to practical scenario #99 and includes variant considerations such as
performance, memory, and maintainability.

Q100. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #100: This question relates to practical scenario #100 and includes variant considerations such as
performance, memory, and maintainability.

Q101. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #101: This question relates to practical scenario #101 and includes variant considerations such as
performance, memory, and maintainability.
Q102. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #102: This question relates to practical scenario #102 and includes variant considerations such as
performance, memory, and maintainability.

Q103. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #103: This question relates to practical scenario #103 and includes variant considerations such as
performance, memory, and maintainability.
Q104. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #104: This question relates to practical scenario #104 and includes variant considerations such as
performance, memory, and maintainability.

Q105. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #105: This question relates to practical scenario #105 and includes variant considerations such as
performance, memory, and maintainability.

Q106. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #106: This question relates to practical scenario #106 and includes variant considerations such as
performance, memory, and maintainability.

Q107. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #107: This question relates to practical scenario #107 and includes variant considerations such as
performance, memory, and maintainability.

Q108. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #108: This question relates to practical scenario #108 and includes variant considerations such as
performance, memory, and maintainability.

Q109. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #109: This question relates to practical scenario #109 and includes variant considerations such as
performance, memory, and maintainability.

Q110. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #110: This question relates to practical scenario #110 and includes variant considerations such as
performance, memory, and maintainability.

Q111. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #111: This question relates to practical scenario #111 and includes variant considerations such as
performance, memory, and maintainability.
Q112. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #112: This question relates to practical scenario #112 and includes variant considerations such as
performance, memory, and maintainability.

Q113. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #113: This question relates to practical scenario #113 and includes variant considerations such as
performance, memory, and maintainability.

Q114. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #114: This question relates to practical scenario #114 and includes variant considerations such as
performance, memory, and maintainability.

Q115. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #115: This question relates to practical scenario #115 and includes variant considerations such as
performance, memory, and maintainability.

Q116. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #116: This question relates to practical scenario #116 and includes variant considerations such as
performance, memory, and maintainability.

Q117. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #117: This question relates to practical scenario #117 and includes variant considerations such as
performance, memory, and maintainability.

Q118. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #118: This question relates to practical scenario #118 and includes variant considerations such as
performance, memory, and maintainability.

Q119. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #119: This question relates to practical scenario #119 and includes variant considerations such as
performance, memory, and maintainability.
Q120. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #120: This question relates to practical scenario #120 and includes variant considerations such as
performance, memory, and maintainability.

Q121. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #121: This question relates to practical scenario #121 and includes variant considerations such as
performance, memory, and maintainability.
Q122. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #122: This question relates to practical scenario #122 and includes variant considerations such as
performance, memory, and maintainability.

Q123. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #123: This question relates to practical scenario #123 and includes variant considerations such as
performance, memory, and maintainability.

Q124. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #124: This question relates to practical scenario #124 and includes variant considerations such as
performance, memory, and maintainability.

Q125. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #125: This question relates to practical scenario #125 and includes variant considerations such as
performance, memory, and maintainability.

Q126. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #126: This question relates to practical scenario #126 and includes variant considerations such as
performance, memory, and maintainability.

Q127. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #127: This question relates to practical scenario #127 and includes variant considerations such as
performance, memory, and maintainability.

Q128. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #128: This question relates to practical scenario #128 and includes variant considerations such as
performance, memory, and maintainability.

Q129. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #129: This question relates to practical scenario #129 and includes variant considerations such as
performance, memory, and maintainability.
Q130. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #130: This question relates to practical scenario #130 and includes variant considerations such as
performance, memory, and maintainability.

Q131. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #131: This question relates to practical scenario #131 and includes variant considerations such as
performance, memory, and maintainability.

Q132. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #132: This question relates to practical scenario #132 and includes variant considerations such as
performance, memory, and maintainability.

Q133. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #133: This question relates to practical scenario #133 and includes variant considerations such as
performance, memory, and maintainability.

Q134. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #134: This question relates to practical scenario #134 and includes variant considerations such as
performance, memory, and maintainability.

Q135. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #135: This question relates to practical scenario #135 and includes variant considerations such as
performance, memory, and maintainability.

Q136. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #136: This question relates to practical scenario #136 and includes variant considerations such as
performance, memory, and maintainability.

Q137. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #137: This question relates to practical scenario #137 and includes variant considerations such as
performance, memory, and maintainability.
Q138. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #138: This question relates to practical scenario #138 and includes variant considerations such as
performance, memory, and maintainability.

Q139. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #139: This question relates to practical scenario #139 and includes variant considerations such as
performance, memory, and maintainability.
Q140. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #140: This question relates to practical scenario #140 and includes variant considerations such as
performance, memory, and maintainability.

Q141. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #141: This question relates to practical scenario #141 and includes variant considerations such as
performance, memory, and maintainability.

Q142. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #142: This question relates to practical scenario #142 and includes variant considerations such as
performance, memory, and maintainability.

Q143. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #143: This question relates to practical scenario #143 and includes variant considerations such as
performance, memory, and maintainability.

Q144. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #144: This question relates to practical scenario #144 and includes variant considerations such as
performance, memory, and maintainability.

Q145. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #145: This question relates to practical scenario #145 and includes variant considerations such as
performance, memory, and maintainability.

Q146. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #146: This question relates to practical scenario #146 and includes variant considerations such as
performance, memory, and maintainability.

Q147. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #147: This question relates to practical scenario #147 and includes variant considerations such as
performance, memory, and maintainability.
Q148. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #148: This question relates to practical scenario #148 and includes variant considerations such as
performance, memory, and maintainability.

Q149. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #149: This question relates to practical scenario #149 and includes variant considerations such as
performance, memory, and maintainability.

Q150. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #150: This question relates to practical scenario #150 and includes variant considerations such as
performance, memory, and maintainability.

Q151. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #151: This question relates to practical scenario #151 and includes variant considerations such as
performance, memory, and maintainability.

Q152. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #152: This question relates to practical scenario #152 and includes variant considerations such as
performance, memory, and maintainability.

Q153. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #153: This question relates to practical scenario #153 and includes variant considerations such as
performance, memory, and maintainability.

Q154. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #154: This question relates to practical scenario #154 and includes variant considerations such as
performance, memory, and maintainability.

Q155. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #155: This question relates to practical scenario #155 and includes variant considerations such as
performance, memory, and maintainability.
Q156. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #156: This question relates to practical scenario #156 and includes variant considerations such as
performance, memory, and maintainability.

Q157. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #157: This question relates to practical scenario #157 and includes variant considerations such as
performance, memory, and maintainability.
Q158. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #158: This question relates to practical scenario #158 and includes variant considerations such as
performance, memory, and maintainability.

Q159. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #159: This question relates to practical scenario #159 and includes variant considerations such as
performance, memory, and maintainability.

Q160. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #160: This question relates to practical scenario #160 and includes variant considerations such as
performance, memory, and maintainability.

Q161. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #161: This question relates to practical scenario #161 and includes variant considerations such as
performance, memory, and maintainability.

Q162. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #162: This question relates to practical scenario #162 and includes variant considerations such as
performance, memory, and maintainability.

Q163. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #163: This question relates to practical scenario #163 and includes variant considerations such as
performance, memory, and maintainability.

Q164. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #164: This question relates to practical scenario #164 and includes variant considerations such as
performance, memory, and maintainability.

Q165. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #165: This question relates to practical scenario #165 and includes variant considerations such as
performance, memory, and maintainability.
Q166. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #166: This question relates to practical scenario #166 and includes variant considerations such as
performance, memory, and maintainability.

Q167. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #167: This question relates to practical scenario #167 and includes variant considerations such as
performance, memory, and maintainability.

Q168. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #168: This question relates to practical scenario #168 and includes variant considerations such as
performance, memory, and maintainability.

Q169. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #169: This question relates to practical scenario #169 and includes variant considerations such as
performance, memory, and maintainability.

Q170. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #170: This question relates to practical scenario #170 and includes variant considerations such as
performance, memory, and maintainability.

Q171. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #171: This question relates to practical scenario #171 and includes variant considerations such as
performance, memory, and maintainability.

Q172. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #172: This question relates to practical scenario #172 and includes variant considerations such as
performance, memory, and maintainability.

Q173. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #173: This question relates to practical scenario #173 and includes variant considerations such as
performance, memory, and maintainability.
Q174. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #174: This question relates to practical scenario #174 and includes variant considerations such as
performance, memory, and maintainability.

Q175. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #175: This question relates to practical scenario #175 and includes variant considerations such as
performance, memory, and maintainability.
Q176. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #176: This question relates to practical scenario #176 and includes variant considerations such as
performance, memory, and maintainability.

Q177. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #177: This question relates to practical scenario #177 and includes variant considerations such as
performance, memory, and maintainability.

Q178. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #178: This question relates to practical scenario #178 and includes variant considerations such as
performance, memory, and maintainability.

Q179. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #179: This question relates to practical scenario #179 and includes variant considerations such as
performance, memory, and maintainability.

Q180. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #180: This question relates to practical scenario #180 and includes variant considerations such as
performance, memory, and maintainability.

Q181. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #181: This question relates to practical scenario #181 and includes variant considerations such as
performance, memory, and maintainability.

Q182. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #182: This question relates to practical scenario #182 and includes variant considerations such as
performance, memory, and maintainability.

Q183. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #183: This question relates to practical scenario #183 and includes variant considerations such as
performance, memory, and maintainability.
Q184. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #184: This question relates to practical scenario #184 and includes variant considerations such as
performance, memory, and maintainability.

Q185. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #185: This question relates to practical scenario #185 and includes variant considerations such as
performance, memory, and maintainability.

Q186. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #186: This question relates to practical scenario #186 and includes variant considerations such as
performance, memory, and maintainability.

Q187. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #187: This question relates to practical scenario #187 and includes variant considerations such as
performance, memory, and maintainability.

Q188. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #188: This question relates to practical scenario #188 and includes variant considerations such as
performance, memory, and maintainability.

Q189. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.

`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #189: This question relates to practical scenario #189 and includes variant considerations such as
performance, memory, and maintainability.

Q190. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #190: This question relates to practical scenario #190 and includes variant considerations such as
performance, memory, and maintainability.

Q191. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #191: This question relates to practical scenario #191 and includes variant considerations such as
performance, memory, and maintainability.
Q192. (Generics) Explain covariance and contravariance with generics in C# and give code
examples.
Covariance lets you use a more derived type than originally specified (output position), contravariance lets you use a
less derived type (input position). C# supports covariance and contravariance for interfaces and delegates using `out`
and `in` modifiers.

Example (covariance):

IEnumerable strings = new List { "a" };


IEnumerable objects = strings; // covariance: IEnumerable

Example (contravariance):

Action actObj = (o) => [Link](o);


Action actStr = actObj; // contravariance: Action
actStr("hello");

Detailed explanation: For `IEnumerable`, `T` is used only for returning values (output), so it's safe to treat
`IEnumerable` as `IEnumerable`; that's covariance. For `Action`, T is an input parameter, so allowing `Action` to be
assigned to `Action` is safe because `Action` accepts any object including strings. Generic variance is limited to
interfaces and delegates and only when type parameters are used solely in input or output positions respectively.

-- Detailed note #192: This question relates to practical scenario #192 and includes variant considerations such as
performance, memory, and maintainability.

Q193. (LINQ & Lambda) Show how to write a LINQ query to group a list of orders by customer and
compute totals. Explain deferred execution and when queries are executed.
Example:

public class Order { public int CustomerId { get; set; } public decimal Amount { get; set; } }

var orders = new List {


new Order { CustomerId = 1, Amount = 10 },
new Order { CustomerId = 2, Amount = 5 },
new Order { CustomerId = 1, Amount = 7 }
};

var totals = orders


.GroupBy(o => [Link])
.Select(g => new { CustomerId = [Link], Total = [Link](x => [Link]) });

foreach (var t in totals)


[Link]($"Customer {[Link]}: {[Link]}");

Deferred execution: LINQ query operators like `Where`, `Select`, `GroupBy` build an expression that is evaluated
when enumerated (e.g., by `foreach`, `ToList`, `ToArray`). To force immediate execution, call materializing operators
like `ToList()` or `ToArray()`. Deferred execution allows queries to reflect the current state of the source collection
when enumerated; use with caution if the source may change.

-- Detailed note #193: This question relates to practical scenario #193 and includes variant considerations such as
performance, memory, and maintainability.
Q194. (Async/Await & Tasks) Demonstrate how to write an async method that calls two IO-bound
operations in parallel and aggregates results. Explain `[Link]` vs awaiting tasks
sequentially.
Example:

public async Task GetTotalAsync()


{
Task a = GetValueFromServiceAAsync();
Task b = GetValueFromServiceBAsync();

// Both tasks started; wait for both


await [Link](a, b);

return [Link] + [Link]; // safe after WhenAll


}

Explanation: Starting the tasks before awaiting allows them to run concurrently. `[Link]` asynchronously waits
for all provided tasks to complete. If instead you `await` each task sequentially (`var x = await a; var y = await b;`) the
second call will only start after the first `await` if task creation is inside the awaited call; to run in parallel ensure the
tasks are started first. Also prefer using `await` rather than `[Link]` to avoid blocking threads; `[Link]` is used
here only after `WhenAll` guarantees completion.

-- Detailed note #194: This question relates to practical scenario #194 and includes variant considerations such as
performance, memory, and maintainability.

Q195. (Delegates & Events) Explain how events work in C#, show defining and subscribing to an
event, and explain why to use `EventHandler`.
Example:

public class ThresholdReachedEventArgs : EventArgs


{
public int Threshold { get; set; }
}

public class Counter


{
public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(int threshold)


{
ThresholdReached?.Invoke(this, new ThresholdReachedEventArgs { Threshold = threshold });
}
}

// Subscribe
var c = new Counter();
[Link] += (s, e) => [Link]($"Threshold: {[Link]}");

Explanation: Events are multicast delegates that allow publishers to expose notifications to subscribers. Using
`EventHandler` provides a standard signature `(object sender, T args)` where `T` derives from `EventArgs`. The
`?.Invoke` pattern avoids race conditions if subscribers become null between check and invocation. Make
event■raising methods `protected virtual` to allow derived classes to override behavior.

-- Detailed note #195: This question relates to practical scenario #195 and includes variant considerations such as
performance, memory, and maintainability.

Q196. (Collections & Memory) Compare `List` vs `LinkedList` vs `ArraySegment` and show when
each is appropriate.
`List`: dynamic array, provides O(1) random access, amortized O(1) append, O(n) insert/remove in middle. Use when
you need random access and frequent iteration.

`LinkedList`: doubly linked list, O(1) insert/remove when you have the node reference, O(n) to find an element. Use
when lots of inserts/removes in middle and node references are kept.

`ArraySegment`: lightweight view over an array without copying. Use to slice arrays efficiently (avoid allocations). Not
a resizable collection.

Example:

var list = new List {1,2,3};


var linked = new LinkedList(list);
var seg = new ArraySegment(new int[]{1,2,3,4}, 1, 2); // views [2,3]

Memory implications: `List` stores data contiguously; `LinkedList` allocates nodes on heap (higher per■element
overhead). For performance critical code prefer `Span`/`Memory` to avoid allocations.

-- Detailed note #196: This question relates to practical scenario #196 and includes variant considerations such as
performance, memory, and maintainability.

Q197. (Exception Handling) Best practices for exception handling in C# and how to create a
custom exception. When to catch vs when to let it bubble?
Best practices: Catch exceptions only when you can handle them or add meaningful context; avoid swallowing
exceptions; prefer specific exception types; use `finally` or `using` to release resources; avoid using exceptions for
flow control.

Custom exception example:

public class InsufficientFundsException : Exception


{
public decimal Amount { get; }
public InsufficientFundsException(decimal amount) : base($"Insufficient funds: {amount}")
{
Amount = amount;
}
}

When to catch: Catch at boundaries where you can translate to user friendly message or recover (e.g., retry). Let it
bubble up when you cannot handle it; centralized logging/error handling middleware is a good place to log and
translate to HTTP responses in web apps.

-- Detailed note #197: This question relates to practical scenario #197 and includes variant considerations such as
performance, memory, and maintainability.

Q198. (Threading & Concurrency) Explain the difference between `lock`, `Monitor`,
`SemaphoreSlim`, and when to use each. Provide a sample using `SemaphoreSlim` for limiting
concurrent access.
`lock(obj)` is a convenient wrapper around `[Link]/Exit` for exclusive access within a process. Use for simple
critical sections.

`Monitor` provides more advanced features: `TryEnter`, pulse/wait signaling.


`SemaphoreSlim` allows limiting concurrent access to a resource with a given maximum count and supports async
waits (`WaitAsync`). Use for throttling asynchronous operations.

Example (SemaphoreSlim):

private static SemaphoreSlim _sem = new SemaphoreSlim(3); // allow 3 concurrent

public async Task DoWorkAsync()


{
await _sem.WaitAsync();
try { await [Link](1000); }
finally { _sem.Release(); }
}

Explanation: Use `lock` for simple sync-only code. For asynchronous code prefer `SemaphoreSlim` as `lock` doesn't
support `await` inside lock safely.

-- Detailed note #198: This question relates to practical scenario #198 and includes variant considerations such as
performance, memory, and maintainability.

Q199. (OOP / Classes & Interfaces) Explain the difference between an abstract class and an
interface in C#. Provide an example when you'd use each.
An abstract class can provide both abstract members (which must be implemented by derived classes) and concrete
implementations. Interfaces define a contract of members that implementing types must provide; in recent C# versions
interfaces can also contain default implementations, but their primary role is a pure contract. Use an abstract class
when you want to share common implementation across related types. Use an interface when you want to define a
capability that can be shared across unrelated types.

Example:

public abstract class Animal


{
public string Name { get; set; }
public abstract void Speak();
public void Eat() { [Link]($"{Name} is eating"); }
}

public interface IPet


{
void Play();
}

public class Dog : Animal, IPet


{
public override void Speak() => [Link]("Woof");
public void Play() => [Link]("Dog plays fetch");
}

Detailed explanation: An abstract class 'Animal' provides a concrete helper 'Eat' and an abstract method 'Speak' that
derived classes must implement. The interface 'IPet' expresses a capability that any class (Dog, Cat, RobotPet) could
implement regardless of its inheritance chain. Abstract classes are suitable for a clear 'is■a' hierarchy; interfaces are
better for composable capabilities and loose coupling.

-- Detailed note #199: This question relates to practical scenario #199 and includes variant considerations such as
performance, memory, and maintainability.

Q200. (Structs & Value Types) When should you use a struct instead of a class in C#? Show a
sample struct and explain boxing concerns.
Use a struct when the type is small, immutable, represents a single value or a small group of values, and will have
short lifetime or be used in high■performance scenarios where allocation overhead matters. Avoid mutable structs
and large structs (>16 bytes is a common heuristic) because copying cost rises.

Example:

public readonly struct Point


{
public double X { get; }
public double Y { get; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other)
=> [Link]((X - other.X)*(X - other.X) + (Y - other.Y)*(Y - other.Y));
}

Boxing explanation: Boxing occurs when a value type is treated as an object or interface; this allocates on the heap
and copies the value. Example `object o = point;` will box the Point. Avoid boxing in hot paths by using generics or
`Span`/`Memory` where appropriate.

-- Detailed note #200: This question relates to practical scenario #200 and includes variant considerations such as
performance, memory, and maintainability.

You might also like