.NET & C# Development · Lesson 10 of 11
Interview Prep: Junior (Q1–Q80)
How to Use This Guide
These questions are asked in junior .NET developer interviews (0-2 years experience). Each includes a short answer for the first 30 seconds, and a full answer for when the interviewer asks you to go deeper.
C# Basics
Q1: What is the difference between int and Int32?
They are exactly the same. int is a C# keyword alias for System.Int32. Both are 32-bit signed integers. The same applies to string ↔ String, bool ↔ Boolean, double ↔ Double.
Q2: What is the difference between var and dynamic?
var: type is inferred at compile time. It's strongly typed — the compiler knows the type and provides IntelliSense and type-checking.dynamic: type is resolved at runtime. No compile-time checking. Used for COM interop, reflection, or working with JSON/scripts.
var x = 42; // compiled as int, fully type-safe
x = "hello"; // ERROR at compile time
dynamic d = 42;
d = "hello"; // fine at compile time, resolved at runtime
d.NonExistent(); // no compile error, RuntimeBinderException at runtimeQ3: What is the difference between const and readonly?
const: compile-time constant. Must be primitive or string. Value baked into IL. Can't be static (implicitly static).readonly: runtime constant. Can be any type, including objects. Set in declaration or constructor. Can be instance or static.
public const double Pi = 3.14159; // compile-time
public readonly DateTime StartTime = DateTime.UtcNow; // set once at runtimeQ4: What is boxing and unboxing?
Boxing: converting a value type (int, bool, struct) to object. Allocates heap memory.
Unboxing: extracting the value type back from object. Requires explicit cast.
int n = 42;
object boxed = n; // boxing — heap allocation
int unboxed = (int)boxed; // unboxing — explicit cast required
// Common pitfall: boxing in collections before generics
ArrayList list = new();
list.Add(42); // boxes every int
// Use List<int> instead — no boxingQ5: What are nullable value types?
Value types (int, bool, DateTime) can't normally be null. int? (which is Nullable<int>) wraps the value type and adds the ability to be null.
int? age = null;
if (age.HasValue)
Console.WriteLine(age.Value);
int result = age ?? 0; // null-coalescing
int result2 = age.GetValueOrDefault(0);Q6: What is string interpolation vs string.Format?
string name = "Alice";
int age = 25;
// Old way
string msg1 = string.Format("Name: {0}, Age: {1}", name, age);
// String interpolation (C# 6+) — more readable
string msg2 = $"Name: {name}, Age: {age}";
// Raw string literals (C# 11) — no escaping needed
string json = """
{
"name": "Alice",
"age": 25
}
""";Q7: What is the difference between == and .Equals() for strings?
For strings, both compare content (value equality) in most cases. However:
==is null-safe:null == nullistrue,null == "x"isfalse.Equals()throwsNullReferenceExceptionif called on null
string a = "hello";
string b = "hello";
Console.WriteLine(a == b); // true (content equality)
Console.WriteLine(a.Equals(b)); // true
string? c = null;
Console.WriteLine(c == null); // true (safe)
// Console.WriteLine(c.Equals("x")); // NullReferenceException!
Console.WriteLine("x".Equals(c)); // false (safe if called on non-null)Q8: What is a StringBuilder and when do you use it?
Strings in C# are immutable — every concatenation creates a new string object. StringBuilder is mutable and efficient for building strings in loops.
// BAD for large loops — creates many string objects
string result = "";
for (int i = 0; i < 10000; i++)
result += i; // 10,000 allocations!
// GOOD — single buffer, resizes as needed
var sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
sb.Append(i);
string result = sb.ToString(); // one allocationObject-Oriented Programming
Q9: What are the four pillars of OOP?
- Encapsulation: hide internal state, expose only what's needed (private fields, public properties)
- Inheritance: derive new classes from existing ones (
class Dog : Animal) - Polymorphism: same interface, different behaviours (
override, virtual methods) - Abstraction: define what something does without specifying how (
abstract class,interface)
Q10: What is the difference between an abstract class and an interface?
| | Abstract Class | Interface | |--|---------------|-----------| | Multiple inheritance | No (C# allows only one base class) | Yes (implement many interfaces) | | Constructor | Yes | No | | Fields | Yes | No (properties only) | | Access modifiers | Yes | All public by default | | Default implementations | Yes | Yes (C# 8+) | | When to use | Shared base with state | Contract/capability |
// Use abstract class: Dog, Cat share Animal's Sleep() logic
public abstract class Animal
{
protected string Name;
public abstract void Speak();
public void Sleep() => Console.WriteLine($"{Name} is sleeping");
}
// Use interface: unrelated classes can all be serialized
public interface ISerializable
{
string Serialize();
}Q11: What is method overloading vs overriding?
- Overloading: same method name, different parameter signatures. Resolved at compile time.
- Overriding: redefine a virtual/abstract method in a derived class. Resolved at runtime.
// Overloading (compile-time)
void Print(string s) { }
void Print(int n) { }
void Print(string s, int n) { }
// Overriding (runtime)
public class Animal { public virtual void Speak() => Console.WriteLine("..."); }
public class Dog : Animal { public override void Speak() => Console.WriteLine("Woof"); }Q12: What is the difference between new and override on a method?
override: polymorphic replacement. The base class reference calls the derived method.new: hides the base method. The base class reference still calls the base method.
class Base { public virtual void M() => Console.WriteLine("Base"); }
class Override : Base { public override void M() => Console.WriteLine("Override"); }
class New : Base { public new void M() => Console.WriteLine("New"); }
Base b1 = new Override();
b1.M(); // "Override" — polymorphism works
Base b2 = new New();
b2.M(); // "Base" — new hides, doesn't replaceQ13: What is a sealed class?
Prevents inheritance from that class. Used when you don't want subclasses, or for performance (compiler can devirtualize calls).
public sealed class SqlCustomerRepository : ICustomerRepository
{
// Nobody can inherit from this
}Q14: What is the this keyword?
Refers to the current instance of the class. Used to:
- Disambiguate fields from parameters (
this.name = name) - Call another constructor (
this(param)) - Return the current instance for method chaining
public class Builder
{
private string _name = "";
private int _age;
public Builder WithName(string name) { _name = name; return this; }
public Builder WithAge(int age) { _age = age; return this; }
public Person Build() => new Person(_name, _age);
}
var person = new Builder().WithName("Alice").WithAge(25).Build();Q15: What is a struct vs class?
| | Struct | Class |
|--|-------|-------|
| Type | Value type | Reference type |
| Memory | Stack (usually) | Heap |
| Assignment | Copies value | Copies reference |
| Inheritance | Cannot inherit | Can inherit |
| Null | Can't be null (unless Nullable<T>) | Can be null |
| Best for | Small, immutable data (Point, Color) | Most objects |
public struct Point { public double X, Y; }
Point a = new Point { X = 1, Y = 2 };
Point b = a; // COPY
b.X = 99;
Console.WriteLine(a.X); // still 1 — a is unaffectedQ16: What is the difference between a shallow copy and a deep copy?
- Shallow copy: copies the object, but reference-type fields still point to the same objects
- Deep copy: copies the object and recursively copies all referenced objects
// Shallow copy (records use this with 'with')
var dto1 = new OrderDto(1, "Alice", items);
var dto2 = dto1 with { Id = 2 }; // items list is still shared!
// Deep copy — manual or via serialization
var json = JsonSerializer.Serialize(original);
var deepCopy = JsonSerializer.Deserialize<OrderDto>(json)!;Collections
Q17: What is the difference between Array, List<T>, and IEnumerable<T>?
Array: fixed size, fastest random access, contiguous memoryList<T>: dynamic size, backed by array, supports Add/RemoveIEnumerable<T>: read-only, forward-only, lazy. Interface that all collections implement.
// Array: fixed size
int[] arr = new int[5];
arr[0] = 1;
// List<T>: dynamic
var list = new List<int> { 1, 2, 3 };
list.Add(4);
list.Remove(2);
// IEnumerable<T>: lazy, composable
IEnumerable<int> evens = list.Where(n => n % 2 == 0); // not evaluated yetQ18: When would you use Dictionary vs List?
Dictionary<K,V>: O(1) lookup by key. Use when you need fast access by a specific identifier.List<T>: O(n) search, O(1) access by index. Use when you iterate in order.
// Dictionary: fast lookup by id
var products = new Dictionary<int, Product>();
var p = products[42]; // O(1)
// List: ordered collection
var ordered = new List<Order>(); // iterate in insertion orderQ19: What is IEnumerable vs IQueryable?
IEnumerable<T>: in-memory operations. LINQ runs in C# on fetched data.IQueryable<T>: translatable queries. LINQ translates to SQL (or other query language) and runs on the data source.
// IQueryable — the WHERE runs in SQL (efficient)
var orders = _context.Orders
.Where(o => o.Status == "pending") // translated to SQL WHERE
.ToList();
// IEnumerable — all orders fetched, then filtered in memory (inefficient!)
IEnumerable<Order> query = _context.Orders.AsEnumerable();
var orders = query.Where(o => o.Status == "pending").ToList();LINQ
Q20: What is deferred vs immediate execution in LINQ?
- Deferred: query is not executed until you iterate it (e.g.,
foreach,ToList()) - Immediate: executed right away (
ToList(),Count(),First(),Sum())
var query = numbers.Where(n => n > 5); // deferred — no execution
numbers.Add(10);
var result = query.ToList(); // executed NOW — includes 10
// Immediate execution
int count = numbers.Where(n => n > 5).Count(); // runs nowQ21: What is the difference between First(), FirstOrDefault(), Single(), and SingleOrDefault()?
| Method | No match | Multiple matches |
|--------|---------|-----------------|
| First() | throws | returns first |
| FirstOrDefault() | returns default (null/0) | returns first |
| Single() | throws | throws |
| SingleOrDefault() | returns default | throws |
Use Single when you expect exactly one result and want an error if that assumption is wrong.
Q22: What is LINQ method syntax vs query syntax?
// Method syntax (most common)
var result = orders
.Where(o => o.Total > 100)
.OrderBy(o => o.CreatedAt)
.Select(o => o.Id);
// Query syntax (SQL-like, less common in practice)
var result = from o in orders
where o.Total > 100
orderby o.CreatedAt
select o.Id;Q23: How does GroupBy work in LINQ?
var ordersByStatus = orders
.GroupBy(o => o.Status)
.Select(g => new
{
Status = g.Key,
Count = g.Count(),
Total = g.Sum(o => o.Total)
})
.ToList();
// Result: [{ Status="pending", Count=5, Total=500 }, ...]Async / Await
Q24: What does async/await actually do?
await pauses the method and returns control to the caller while waiting for the task to complete. The thread is freed to do other work. When the awaited task finishes, the method resumes.
What it does NOT do: create new threads. Async code is about not blocking threads — not about parallelism.
public async Task<string> GetDataAsync()
{
// Thread is freed during the HTTP call
string data = await httpClient.GetStringAsync(url);
// Method resumes here when HTTP call completes
return data.ToUpper();
}Q25: What is the difference between Task and ValueTask?
Task<T>: always allocates on the heap. Use for most async methods.ValueTask<T>: can avoid allocation if result is available synchronously. Use in hot code paths (e.g., cache hits) where the operation is often synchronous.
Q26: What happens if you don't await an async method?
The method starts but you don't wait for it to complete. Exceptions are silently swallowed.
// WRONG — no await, exception swallowed
DoWorkAsync();
// CORRECT — await it
await DoWorkAsync();
// If intentional fire-and-forget, suppress the warning:
_ = Task.Run(() => DoWorkAsync());Q27: What is ConfigureAwait(false) and when should you use it?
By default, await captures the current synchronization context and resumes on it. In a web server (ASP.NET Core), there's no synchronization context, so it doesn't matter. But in UI frameworks (WPF, WinForms) or older ASP.NET, it can cause deadlocks.
In library code: use ConfigureAwait(false) to avoid capturing context.
In application/controller code: don't bother — ASP.NET Core has no sync context.
Q28: What is Task.WhenAll vs Task.WhenAny?
// WhenAll: wait for all tasks, run concurrently
var (users, orders) = await (
GetUsersAsync(), // both start immediately
GetOrdersAsync() // runs concurrently with GetUsersAsync
);
// WhenAny: continue when the first task completes
var fastResult = await Task.WhenAny(task1, task2, task3);ASP.NET Core
Q29: What is the difference between AddTransient, AddScoped, and AddSingleton?
- Transient: new instance every time the service is resolved
- Scoped: one instance per HTTP request (scope)
- Singleton: one instance for the entire application lifetime
services.AddTransient<IEmailSender, SmtpEmailSender>(); // new each time
services.AddScoped<IOrderRepository, SqlOrderRepository>(); // new per request
services.AddSingleton<IConfiguration>(...); // one foreverCommon rule: DbContext = Scoped, HTTP clients = registered as factory/typed client.
Q30: What is middleware in ASP.NET Core?
Middleware is a component in the request pipeline. Each piece of middleware can:
- Process the incoming request
- Pass the request to the next middleware (
await next(context)) - Process the outgoing response
Common middleware: authentication, CORS, routing, logging, error handling.
Q31: What is the difference between IActionResult and ActionResult<T>?
IActionResult: non-generic, can return any result typeActionResult<T>: generic, gives Swagger/OpenAPI accurate response type information
// IActionResult
public IActionResult Get(int id) => id > 0 ? Ok(new Product()) : NotFound();
// ActionResult<T> — Swagger knows it returns Product on 200
public ActionResult<Product> Get(int id) => id > 0 ? new Product() : NotFound();Q32: What is model binding in ASP.NET Core?
Automatic extraction of values from HTTP requests into method parameters.
[HttpGet("{id}")]
public IActionResult Get(
int id, // from route
[FromQuery] string? filter, // from query string
[FromHeader] string? apiKey, // from header
[FromBody] UpdateRequest request, // from JSON body
CancellationToken ct) // injected by frameworkQ33: What is [ApiController] attribute?
Enables:
- Automatic model validation (returns 400 if model state is invalid)
- Automatic
[FromBody]on complex POST parameters - Better problem details responses
Q34: What is ILogger and how do you use it?
public class OrderService
{
private readonly ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger) => _logger = logger;
public async Task ProcessAsync(int orderId)
{
_logger.LogInformation("Processing order {OrderId}", orderId);
try { /* ... */ }
catch (Exception ex)
{
_logger.LogError(ex, "Failed to process order {OrderId}", orderId);
throw;
}
}
}Log levels: LogTrace < LogDebug < LogInformation < LogWarning < LogError < LogCritical
Use structured logging parameters ({OrderId}) not string interpolation — allows log systems to index by property.
Q35: What is dependency injection and why is it useful?
DI is a pattern where a class receives its dependencies from outside rather than creating them itself.
Benefits:
- Testability: inject mock implementations in tests
- Loose coupling: depend on interfaces, not concrete classes
- Lifetime management: framework manages object creation and disposal
// Without DI — tightly coupled, hard to test
public class OrderService
{
private readonly SmtpEmailSender _email = new SmtpEmailSender("smtp.gmail.com");
}
// With DI — loosely coupled, easy to test
public class OrderService
{
private readonly IEmailSender _email;
public OrderService(IEmailSender email) => _email = email;
}Q36–Q80: Quick-fire Questions
Q36: What is the difference between throw and throw ex?
throw re-throws the current exception preserving the original stack trace. throw ex resets the stack trace to the current location — you lose where the exception originally happened. Always use throw.
Q37: What is a using statement?
Automatically calls Dispose() on objects that implement IDisposable when the block exits, even on exceptions.
using (var stream = File.OpenRead("file.txt")) { ... }
// or modern style:
using var stream = File.OpenRead("file.txt");
// Disposed at end of enclosing scopeQ38: What is IDisposable?
An interface with one method: void Dispose(). Implement it when your class holds unmanaged resources (file handles, database connections, HTTP clients). The using statement calls it automatically.
Q39: What is the difference between Dispose() and garbage collection?
GC frees managed memory automatically. Dispose() frees unmanaged resources (files, connections) immediately when you're done. Don't wait for GC to release a database connection — Dispose() it right away.
Q40: What is a static class? A class that cannot be instantiated and only has static members. Used for utility/extension methods and global state.
public static class MathUtils
{
public static double Square(double x) => x * x;
}Q41: What are extension methods? Methods that extend a type without modifying it.
public static class StringExtensions
{
public static bool IsValidEmail(this string email)
=> email.Contains('@') && email.Contains('.');
}
// Usage: "alice@example.com".IsValidEmail()Q42: What is a lambda expression?
An anonymous function using the => arrow syntax.
Func<int, int> square = x => x * x;
var evens = numbers.Where(n => n % 2 == 0);Q43: What is a delegate?
A type-safe function pointer. Func<T, TResult>, Action<T>, and Predicate<T> are built-in delegate types.
Q44: What is SOLID? 5 object-oriented design principles:
- Single Responsibility — one reason to change
- Open/Closed — open for extension, closed for modification
- Liskov Substitution — subtypes must be substitutable for base types
- Interface Segregation — many specific interfaces > one general
- Dependency Inversion — depend on abstractions, not concretions
Q45: What is a factory pattern? An object that creates other objects. Decouples creation from usage.
public interface IEmailSenderFactory { IEmailSender Create(string provider); }Q46: What is a singleton pattern?
Ensures only one instance of a class exists. In .NET: register with AddSingleton or use a static field with lazy initialization.
Q47: What is Lazy<T>?
Thread-safe lazy initialization — the value is only created when first accessed.
private static readonly Lazy<ExpensiveResource> _resource =
new(() => new ExpensiveResource());
ExpensiveResource r = _resource.Value; // created on first accessQ48: What is an enum? A named set of integral constants.
public enum OrderStatus { Pending, Processing, Shipped, Delivered, Cancelled }
OrderStatus status = OrderStatus.Pending;
// Can convert: (int)status = 0, Enum.Parse<OrderStatus>("Pending")Q49: What is a partial class? A class definition split across multiple files. All parts must be in the same assembly. EF Core uses this for generated code.
// File1.cs
public partial class Customer { public string Name { get; set; } = ""; }
// File2.cs
public partial class Customer { public string GetDisplay() => Name; }Q50: What is nameof()?
Returns the name of a variable, type, or member as a string. Compile-time safe (refactor-proof).
throw new ArgumentNullException(nameof(customer));
// Instead of: throw new ArgumentNullException("customer");Q51: What is the difference between IEnumerable<T> and ICollection<T>?
IEnumerable<T>: read-only, forward-only iteration. ICollection<T> extends it with Count, Add, Remove, Contains.
Q52: What is an anonymous type? A type without a name, defined inline.
var summary = new { Name = "Alice", Total = 999.99 };
Console.WriteLine(summary.Name);Q53: What is a tuple? A lightweight data structure for grouping values without a class.
(string name, int age) = ("Alice", 25);
var result = (Min: 1, Max: 100);
Console.WriteLine(result.Min);Q54: What is pattern matching? Testing a value against a pattern and extracting data from it.
if (obj is string s && s.Length > 5) Console.WriteLine(s);
string msg = shape switch { Circle c => $"r={c.Radius}", _ => "other" };Q55: What is string comparison best practice?
Use StringComparison.OrdinalIgnoreCase for case-insensitive checks. Don't use ToUpper() or ToLower() for comparisons — it allocates a new string.
if (status.Equals("active", StringComparison.OrdinalIgnoreCase)) { }Q56: What is Environment.NewLine vs \n?
Environment.NewLine is platform-specific (\r\n on Windows, \n on Linux/Mac). For web/network protocols, always use \n or \r\n explicitly.
Q57: What is Math.Ceiling, Math.Floor, and Math.Round?
Floor: round down (4.9 → 4)Ceiling: round up (4.1 → 5)Round(x, 2, MidpointRounding.AwayFromZero): standard rounding
Q58: How do you convert a string to an integer?
int n = int.Parse("42"); // throws on invalid
bool ok = int.TryParse("42", out n); // safe
int n2 = Convert.ToInt32("42"); // Convert.ToInt32(null) returns 0Q59: What is the checked keyword?
Makes arithmetic throw OverflowException on integer overflow (normally silently wraps).
checked { int result = int.MaxValue + 1; } // throws OverflowExceptionQ60: What is object.ReferenceEquals?
Checks if two references point to the same object (ignoring any == overload).
string a = "hello";
string b = new string("hello");
Console.WriteLine(object.ReferenceEquals(a, b)); // false (different objects)
Console.WriteLine(a == b); // true (same content)Q61: What is string interning?
.NET maintains a pool of string literals. Identical string literals share the same memory. string.Intern(s) manually interns a string.
Q62: What is a Span<T>?
A stack-allocated, type-safe window over memory (array slice). Used in high-performance code to avoid allocations.
string text = "Hello, World!";
ReadOnlySpan<char> slice = text.AsSpan(0, 5); // "Hello" — no allocationQ63: What is Memory<T> vs Span<T>?
Span<T> is stack-only — can't be stored in a class field or used across await. Memory<T> can be stored and used asynchronously.
Q64: What is the difference between == and Object.Equals for value types?
For value types (structs, primitives), == compares values. Object.Equals does the same unless overridden. For classes, == compares references unless overloaded.
Q65: What is IComparable<T> vs IEquatable<T>?
IComparable<T>: supports ordering (<, >, sorting). IEquatable<T>: supports equality comparison without boxing.
Q66: What is Enumerable.Range?
Generates a sequence of integers.
var numbers = Enumerable.Range(1, 10); // 1,2,3,...,10
var squares = Enumerable.Range(1, 10).Select(n => n * n);Q67: What is the difference between Concat, Append, and Union?
Concat: combines two sequences (keeps duplicates)Append: adds one element to the endUnion: combines and removes duplicates
Q68: What is SelectMany?
Flattens a sequence of sequences.
var allItems = orders.SelectMany(o => o.Items); // all items from all orders in one listQ69: What is Zip in LINQ?
Combines two sequences element-by-element.
var combined = names.Zip(ages, (name, age) => $"{name} is {age}");Q70: What is Aggregate in LINQ?
Applies an accumulator function over a sequence.
int product = new[] { 1,2,3,4,5 }.Aggregate((acc, x) => acc * x); // 120Q71: What is the ?: ternary operator?
string result = age >= 18 ? "Adult" : "Minor";Q72: What is the difference between as and explicit cast (T)?
(T)obj: throwsInvalidCastExceptionif cast failsobj as T: returns null if cast fails (only for reference types and nullable)
var s = obj as string; // null if not a string
var s2 = (string)obj; // throws if not a stringQ73: What is Convert.ToInt32 vs int.Parse vs (int)?
int.Parse("42"): string to int, throws on null or invalidConvert.ToInt32("42"): string to int, returns 0 on null, throws on invalid(int)3.9: truncates double to int (3)
Q74: What does params keyword do?
Allows a method to accept variable number of arguments as an array.
static int Sum(params int[] numbers) => numbers.Sum();
Sum(1, 2, 3); // works
Sum(new[] { 1, 2, 3 }); // also worksQ75: What is yield return?
Creates a lazy iterator — values are produced one at a time on demand.
IEnumerable<int> GetEvens(int max)
{
for (int i = 0; i <= max; i += 2)
yield return i; // returns one at a time
}Q76: What is the difference between async void and async Task?
async void can't be awaited and exceptions are unhandled. Only use for event handlers. Always use async Task otherwise.
Q77: What is CancellationToken?
A token that signals a cancellation request. Pass it through the call chain so operations can stop early (e.g., user navigates away, request timeout).
app.MapGet("/data", async (CancellationToken ct) =>
{
await _service.GetDataAsync(ct); // stops if request is cancelled
});Q78: What is IHostedService?
Interface for background services in ASP.NET Core — runs on a background thread during app lifetime.
Q79: What is the difference between HttpClient and IHttpClientFactory?
new HttpClient() in loops causes socket exhaustion. IHttpClientFactory manages a pool of HTTP handlers and reuses them efficiently.
// Register: services.AddHttpClient<WeatherService>();
// Inject: private readonly HttpClient _client;Q80: What is the [Required] attribute?
A data annotation that marks a property as required for model validation. Works with model binding validation in ASP.NET Core.