General .Net Flashcards

(34 cards)

1
Q

What happens If you put a more general exception type before a more specific one?

A

the compiler will give you an error like:

A previous catch clause already catches all exceptions of this or a super type

For example:

catch (Exception ex) // general
catch (NullReferenceException ex) // specific

❌ This won’t compile, because the NullReferenceException will never be reached (since Exception already covers it).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

what happens here

try
{
throw new NullReferenceException();
}
catch (NullReferenceException ex)
{
Console.WriteLine(“Caught NullReferenceException”);
}
catch (ArgumentException ex)
{
Console.WriteLine(“Caught ArgumentException”);
}
catch (Exception ex)
{
Console.WriteLine(“Caught general Exception”);
}

A

C# checks the catch blocks in order, top to bottom.

When it finds the first matching type, it executes that block.

Here, since you threw a NullReferenceException, it matches the first catch (NullReferenceException ex) and enters there.

The later catch blocks (ArgumentException, Exception) are skipped.

✅ So, in your scenario:

NullReferenceException → enters first catch.

If it were ArgumentException → enters the second catch.

If it were something else (e.g. InvalidOperationException) → falls through to the last catch (Exception).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

what is the purpose of when keyword in exception handling?

A

In C#, you can add a filter to a catch block like this:

try
{
// some code
}
catch (Exception ex) when (ex.Message.Contains(“timeout”))
{
// Handle only timeout-related exceptions
}
catch (Exception ex)
{
// Handle all other exceptions
}

The when filter is evaluated before the catch block is chosen.

If the filter evaluates to true, that catch handles the exception.

If it evaluates to false, the runtime will continue searching for another matching catch block, as if that block didn’t exist.

This is different from putting an if inside the catch block, because with when:

The stack trace isn’t altered (since the exception is only “caught” if the filter passes).

The runtime can continue looking for other matches instead of forcing you to rethrow.

Filters also let you write more precise exception handling, without nesting lots of if checks inside the catch.

So yes, it absolutely affects which block is chosen: the runtime goes top-to-bottom through the catch list, but only picks the first one where both the type matches and the filter evaluates to true.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What happens when the below code executes?

try
{
throw new InvalidOperationException(“timeout error”);
}
catch (InvalidOperationException ex) when (ex.Message.Contains(“disk”))
{
Console.WriteLine(“Handled disk issue”);
}
catch (InvalidOperationException ex) when (ex.Message.Contains(“timeout”))
{
Console.WriteLine(“Handled timeout issue”);
}
catch (Exception ex)
{
Console.WriteLine(“Handled general exception”);
}

A

Exception is thrown
throw new InvalidOperationException(“timeout error”);

Runtime scans catch blocks in order

First block: catch (InvalidOperationException ex) when (ex.Message.Contains(“disk”))

Type matches (InvalidOperationException).

Filter is evaluated: “timeout error”.Contains(“disk”) → false.

Because the filter is false, this block is skipped.

Next block

Second block: catch (InvalidOperationException ex) when (ex.Message.Contains(“timeout”))

Type matches.

Filter is evaluated: “timeout error”.Contains(“timeout”) → true.

Filter passes → this block handles the exception.

“Handled timeout issue” is printed.

Other blocks are ignored
The catch (Exception ex) block is never reached because the exception was already handled.

Important things to highlight

Filters decide before entry: If a filter fails, it’s as if the block doesn’t exist.

Stack trace preservation: Because the exception is only “caught” if the filter passes, the original stack trace isn’t reset (unlike catching and rethrowing).

Fallback: If all filters return false, the runtime keeps searching down until it finds another matching catch (or crashes if none exist).

👉 This makes when filters super useful for fine-grained exception handling without deep nesting.

Do you want me to also contrast this with the alternative (if inside the catch) so you can clearly show why when is better?

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q
A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

How to preserve stack trace even if you catch the exception?

A

If you do just throw; inside a catch, the stack trace is preserved.

If you do throw ex;, the stack trace is reset to the current point (you lose the original call info).

Example
try
{
DangerousMethod();
}
catch (Exception ex)
{
Console.WriteLine(“Logging exception…”);
throw; // preserves original stack trace
}

✅ The stack trace still points to the line in DangerousMethod() where the exception originated.

Common pitfalls
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex; // ❌ resets the stack trace
}

Now the stack trace shows only the rethrow location, not where it originally happened.

Best practices to preserve stack trace

Use throw; instead of throw ex;
This is the simplest and safest.

Use ExceptionDispatchInfo if you need to rethrow later
If you want to capture an exception and rethrow it somewhere else (not immediately), you can use System.Runtime.ExceptionServices.ExceptionDispatchInfo:

using System;
using System.Runtime.ExceptionServices;

try
{
DangerousMethod();
}
catch (Exception ex)
{
var edi = ExceptionDispatchInfo.Capture(ex);
// do some work, maybe pass edi around
edi.Throw(); // preserves the original stack trace
}

👉 So the answer is:

Use plain throw; inside the same catch block.

Use ExceptionDispatchInfo.Capture(…).Throw(); if you need to rethrow later, while still preserving the original stack trace.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What does a when filter in a catch block do in C#?

A

It evaluates a condition before the catch block is chosen; if false, the block is skipped.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

How is a when filter different from an if inside a catch?

A

With when, the exception isn’t caught unless the filter passes, so no rethrow is needed and the stack trace isn’t altered.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What happens if the when filter evaluates to false?

A

The runtime continues searching for another matching catch block.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Why are when filters stack-trace friendly?

A

Because the exception is only caught if the filter passes, so the stack trace remains untouched if skipped.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

How do you preserve the stack trace when rethrowing inside the same catch?

A

Use throw; instead of throw ex;.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What’s the problem with throw ex;?

A

It resets the stack trace to the rethrow point, losing the original call location.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How can you preserve the stack trace if you want to rethrow the exception later (not immediately)?

A

Use ExceptionDispatchInfo.Capture(ex) and later call edi.Throw().

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Do you need to wrap the exception when using ExceptionDispatchInfo.Capture?

A

No, it captures the existing exception and its stack trace; you just call edi.Throw() to rethrow it.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What’s the difference between throw; and ExceptionDispatchInfo.Throw()?

A

throw; only works inside the same catch, while ExceptionDispatchInfo.Throw() works anywhere and still preserves the original stack trace.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What is StringBuilder?

A

A mutable sequence of characters in C# that allows efficient string manipulation.

17
Q

Why use StringBuilder instead of a string?

A

Strings are immutable. Concatenating strings repeatedly creates new objects, while StringBuilder modifies the same buffer.

18
Q

How do you create a StringBuilder?

A

new StringBuilder(), new StringBuilder(“Hello”), or new StringBuilder(50) (initial capacity).

19
Q

What happens if the buffer exceeds capacity?

A

A larger buffer is allocated, old content is copied, and new content is added

20
Q

Why is StringBuilder memory efficient?

A

Modifies the internal buffer and only creates a string on ToString(), reducing memory allocations and GC pressure.

21
Q

When should you use StringBuilder?

A

In loops with many concatenations or repeated string modifications.

22
Q

What are the advantages of using HttpClientFactory

A

Resilience: Integrates with Polly (retry, circuit breaker, fallback).

Centralized configuration for headers, base URLs, policies.

Logging + metrics built-in.

Avoids socket exhaustion by pooling handlers correctly.

23
Q

What problem does HttpClientFactory solve?

A

It manages HttpClient lifetimes to prevent socket exhaustion and handle DNS refresh issues.

24
Q

How do you register HttpClients?

A

services.AddHttpClient();

25
How does HttpClientFactory improve resilience?
Supports Polly policies like retries, circuit breakers, timeouts
26
How is HttpClient lifecycle managed internally when HttpClientFactory is used?
It reuses underlying HttpMessageHandler instances with connection pooling.
27
How can retry be implemented in HttpClientFactory?
public void ConfigureServices(IServiceCollection services) { services.AddHttpClient("RetryClient") .AddPolicyHandler(GetRetryPolicy()); } private IAsyncPolicy GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() // Handles 5xx, 408 and network errors .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.TooManyRequests) // 429 .WaitAndRetryAsync( retryCount: 3, sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), // 2s, 4s, 8s onRetry: (outcome, timespan, retryAttempt, context) => { Console.WriteLine($"Retry {retryAttempt} after {timespan.TotalSeconds}s due to {outcome.Result?.StatusCode}"); }); }
28
what is wrong with this code? public async Task GetData() { using (var client = new HttpClient()) // ❌ Bad practice { return await client.GetStringAsync("https://api.example.com/data"); } }
At first glance, this looks okay because HttpClient is IDisposable. But disposal does not close TCP connections immediately. Instead, the underlying sockets linger in a TIME_WAIT state for ~2 minutes. ➡️ If your app makes frequent requests and recreates HttpClient each time, you can hit socket exhaustion (running out of available ports).
29
When would using a struct instead of a class cause performance issues?
Using a struct instead of a class can cause performance issues if the struct is large and copied frequently, since structs are value types and each assignment or method call copies the entire object. This increases memory usage and CPU overhead. Another issue is boxing and unboxing, which happens when a struct is converted to an object or interface type, leading to additional allocations on the heap. In these cases, a class is more efficient because only the reference is copied.
30
Can you explain the difference between struct and class in C#? When would you choose one over the other?
In C#, a struct is a value type, while a class is a reference type. Structs are usually stored on the stack (or inline), and their values are copied when assigned or passed. Classes are stored on the heap, and variables hold a reference to the object. Unlike classes, structs cannot inherit from another struct or class, though they can implement interfaces. Structs also cannot define a parameterless constructor. Typically, I use structs for small, lightweight, immutable data (like Point or DateTime) and classes for larger, more complex objects that need inheritance, polymorphism, or reference semantics.
31
What is the difference between IEnumerable, ICollection, IList, and IReadOnlyList in C#? When would you choose one over the others?
IEnumerable is the most basic collection interface. It provides deferred iteration over a sequence of elements but does not allow modification. ICollection inherits from IEnumerable and adds methods for adding, removing, and counting items (Add, Remove, Count, Clear). It represents a modifiable collection. IList inherits from ICollection and adds index-based access (this[int index]) and insert/remove at a specific position, making it suitable for collections where order matters and you need random access. IReadOnlyList represents a read-only, indexable collection. You can access items by index and iterate, but cannot modify the collection. ✅ When to use each: IEnumerable → when you just need to iterate over a sequence. ICollection → when you need modification operations like add/remove. IList → when you need index-based access and order-sensitive operations. IReadOnlyList → when you want to expose a collection safely without allowing modifications.
32
Can you explain the difference between Task, ValueTask, and void in asynchronous C# methods? When would you use each?
In C#, Task represents an asynchronous operation and is part of the Task Parallel Library (TPL). It can return a result (Task) or be non-returning (Task). void is used for asynchronous event handlers, but it should generally be avoided in async methods because it cannot be awaited and exceptions cannot be caught easily. ValueTask is a more memory-efficient alternative to Task for methods that may complete synchronously and frequently return a result immediately. Unlike Task, ValueTask avoids allocating a new object on the heap in these cases. However, ValueTask comes with some restrictions, like it should not be awaited multiple times and is more complex to manage correctly. ✅ Usage guidance: Use Task for most async methods. Use ValueTask for performance-sensitive, frequently-completing synchronous operations. Use void only for event handlers.
33
Can you explain the difference between ref, out, and in parameters in C#? When would you use each?
“ref passes a variable by reference and allows reading and writing, out passes by reference for returning values and must be assigned in the method, and in passes by reference as read-only, useful for large structs to avoid copying.” ref: Passes a variable by reference. The variable must be initialized before being passed, and the method can read and modify it. out: Also passes a variable by reference, but it is intended to return values from a method. The variable does not need to be initialized before being passed, but the method must assign a value before returning. in: Passes a variable by reference for read-only purposes. The method cannot modify the variable, making it useful for performance when passing large structs without copying. ✅ When to use: ref → when you need to read and write a value in the method. out → when you want to return multiple values from a method. in → when you want to avoid copying large structs but don’t want the method to modify them.
34