200 Practical CSharp Coding QA Detailed
200 Practical CSharp Coding QA Detailed
(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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
`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):
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:
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:
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):
Example (contravariance):
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; } }
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:
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:
// 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:
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.
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.
Example (SemaphoreSlim):
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:
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:
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.