Seventeen .NET Developer Interview Questions That Actually Matter
I’ve been hiring .NET developers for years, and I’ve learned that most interview questions are either too basic or too theoretical. The questions that actually matter are the ones that reveal how someone thinks about real-world problems in C# and .NET development.
When I’m evaluating candidates for six-figure positions, I want to see how they approach practical scenarios. That’s why I often use LINQPad to test code snippets during interviews—it’s perfect for quickly demonstrating concepts and showing how different approaches work in practice.
Here are the seventeen questions I use to separate senior .NET developers from juniors, along with the answers I’m looking for:
1. How would you handle a memory leak in a long-running .NET application?
Answer: I’d start by using tools like dotMemory or PerfView to identify what’s holding references. Common causes include event handlers not being unsubscribed, static collections growing indefinitely, or IDisposable objects not being disposed. I’d look for patterns like static dictionaries that accumulate data, event subscriptions that outlive their intended scope, or unmanaged resources not being properly released. The fix usually involves implementing IDisposable patterns correctly, using weak references where appropriate, or restructuring the code to avoid long-lived references.
2. Explain the difference between async/await and Task.Run()
Answer: async/await is for making existing synchronous code asynchronous without blocking threads. It’s perfect for I/O operations like database calls or HTTP requests. Task.Run() is for offloading CPU-intensive work to a background thread. You’d use async/await when you’re already doing I/O work and want to free up the thread. You’d use Task.Run() when you have CPU-bound work that would block the UI thread or ASP.NET request thread. The key is that async/await doesn’t create new threads—it just frees up the existing one during I/O waits.
3. What’s the difference between IEnumerable and IQueryable?
Answer: IEnumerable works with in-memory collections and executes LINQ operations in C#. IQueryable works with external data sources like databases and translates LINQ operations into the underlying query language (like SQL). When you use IEnumerable, all data is loaded into memory first, then filtered. With IQueryable, the filtering happens at the data source level, which is much more efficient for large datasets. You’d use IEnumerable for small, in-memory collections and IQueryable when working with Entity Framework or other ORMs.
4. How would you implement a custom exception in C#?
Answer: I’d create a class that inherits from Exception or one of its derived classes like ApplicationException. I’d include constructors that call the base constructor, and I’d make sure to include a message and optionally an inner exception. I’d also implement the serialization constructor if the exception needs to be serializable. The key is following the .NET exception design guidelines—providing meaningful error messages and including the original exception as the inner exception when wrapping other exceptions.
5. Explain the difference between value types and reference types in C#
Answer: Value types (structs, enums, primitives) are stored on the stack and copied when passed around. Reference types (classes, interfaces, delegates) are stored on the heap with references on the stack. Value types are passed by value by default, while reference types are passed by reference. This means modifying a value type parameter doesn’t affect the original, but modifying a reference type parameter does. The choice between them affects performance, memory usage, and behavior when passing data between methods.
6. Explain the difference between First() and FirstOrDefault()
Answer: First() throws an exception if no elements match the condition, while FirstOrDefault() returns the default value (null for reference types, 0 for value types). I’d use First() when I expect at least one element and want to fail fast if none exist. I’d use FirstOrDefault() when it’s valid for no elements to exist and I want to handle that case gracefully. The choice depends on whether an empty result is an error condition or a valid state in your application logic.
7. How do you implement a custom attribute in C#?
Answer: I’d create a class that inherits from Attribute and includes the AttributeUsage attribute to specify where it can be applied. I’d add properties to store data and implement constructors to initialize the attribute. I’d use reflection to read the attribute data at runtime. The key is understanding that attributes are metadata that can be read through reflection, and they’re useful for declarative programming patterns like validation, serialization, or dependency injection.
8. What’s the difference between String and StringBuilder?
Answer: String is immutable—every operation creates a new string object. StringBuilder is mutable and designed for building strings efficiently. I’d use String for simple concatenation or when I don’t need to modify the string. I’d use StringBuilder when I need to build a string through multiple operations, especially in loops. StringBuilder is much more efficient for repeated concatenation because it doesn’t create new objects each time. The choice affects performance and memory usage significantly for string-heavy operations.
9. Explain the difference between virtual and abstract methods
Answer: Virtual methods have a default implementation that can be overridden by derived classes. Abstract methods have no implementation and must be overridden by derived classes. I’d use virtual when I want to provide a default behavior that derived classes can optionally override. I’d use abstract when I want to force derived classes to provide their own implementation. Abstract methods can only exist in abstract classes, while virtual methods can exist in any class. This affects the design flexibility and the contract with derived classes.
Ready to Ace Your .NET Developer Interview?
What You'll Get:
Real Mock Interviews with senior .NET engineers
Detailed Feedback on your technical responses
Hire/No-Hire Decision with specific improvement areas
Performance Analysis across all interview categories
Actionable Next Steps to strengthen your weak points
Why Our Prep Course Works:
Unlike generic practice questions, our course simulates the actual interview experience. You'll receive actual feedback hiring managers normally hide from candidates but in a safe, preparation-focused environment with no actual job on the line.
Ready to transform your interview performance?
*Note: This is a preparation course only. No actual job opportunities are associated with this program.*
10. What’s the difference between readonly and const?
Answer: Const is a compile-time constant that must be initialized at declaration and can’t be changed. Readonly is a runtime constant that can be initialized at declaration or in the constructor and can’t be changed after initialization. I’d use const for values that are truly constant and known at compile time. I’d use readonly for values that are constant but might be calculated at runtime or set in the constructor. The choice affects when the value is determined and how flexible the initialization can be.
11. Explain the difference between ref and out parameters
Answer: Both allow passing parameters by reference, but ref requires the variable to be initialized before the method call, while out doesn’t. Out parameters must be assigned within the method, while ref parameters can be read or written. I’d use ref when I want to pass a value by reference and potentially modify it. I’d use out when I want the method to return multiple values or when the parameter is only for output. The choice affects the contract with the calling code and how the parameter is used.
12. What’s the difference between Task and ValueTask?
Answer: Task is a reference type that allocates on the heap, while ValueTask is a value type that can avoid heap allocations for synchronous results. I’d use Task for most async operations. I’d use ValueTask when the operation is likely to complete synchronously or when I’m optimizing for performance in high-throughput scenarios. The key is understanding that ValueTask can reduce garbage collection pressure but has different usage patterns—you can only await it once, unlike Task which can be awaited multiple times.
13. Explain the compilation process in .NET from source code to running application.
Answer: The .NET compilation process has two main steps. First, the C# compiler converts source code into Intermediate Language (IL) code and creates a .dll or .exe assembly. This IL code works on any platform. Then, when you run the application, the Just-In-Time (JIT) compiler converts the IL code into native machine code that can run on your specific CPU. The Common Language Runtime (CLR) executes this code and handles things like memory management and security.
14. What are the different types of constructors in C#?
Answer: There are several types of constructors in C#:
-
Default constructor - Created automatically by the compiler if no other constructor exists. Takes no parameters and initializes fields to default values.
-
Parameterless constructor - Explicitly written with no parameters. Useful when you need custom initialization but don’t need any input values.
-
Parameterized constructor - Takes parameters to initialize object state. Most common type, allows creating objects with specific initial values.
-
Static constructor - Called once before any static members are accessed or instances are created. Used to initialize static state.
-
Private constructor - Prevents instantiation from outside the class. Often used in singleton pattern or static utility classes.
15. What is the meaning of boxing and unboxing in .NET?
Answer: Boxing is when .NET wraps a value type (like int or bool) in a reference type object to store it on the heap. Unboxing is the reverse - extracting the value type from the boxed object. I’d avoid boxing/unboxing when possible because it hurts performance - it creates garbage for the collector and takes CPU time. Common examples are when you pass a value type to a method taking object, or when you store value types in collections that work with object references. Using generics or specific value type collections helps avoid boxing.
16. What is the yield
keyword used for in C#?
Answer: The yield
keyword is used to create an iterator method that returns an IEnumerable sequence one element at a time. I’d use it when I want to generate a sequence of values without storing them all in memory at once. It’s memory-efficient because it only computes values as they’re requested. The compiler transforms the method into a state machine that remembers its position between calls.
17. Explain the difference between struct
and class
in C#?
Answer: Structs and classes have key differences in behavior and usage:
-
Value type vs Reference type - Structs are value types stored on the stack, while classes are reference types stored on the heap. This affects how they’re passed around and copied.
-
Inheritance - Structs can’t inherit from other structs (except they implicitly inherit from ValueType), while classes support full inheritance hierarchies. Structs can implement interfaces though.
-
Default behavior - Struct fields are automatically initialized to their default values, while class fields start as null unless explicitly initialized.
-
Performance implications - Structs avoid heap allocation and garbage collection overhead, making them more efficient for small, simple types that are frequently created and destroyed.
I’d use structs for small, immutable types that represent a single value or a small group of related values (like Point or Color). I’d use classes for larger types, types that need inheritance, or types that represent complex objects with behavior. The choice affects performance, memory usage, and how the type behaves when passed between methods.
Why These Questions Matter
These questions reveal more than just technical knowledge. They show how a developer thinks about performance, memory management, and real-world scenarios. When I’m hiring for six-figure positions, I need developers who understand not just how to write code, but how to write code that scales, performs, and maintains well.
The best .NET developers I’ve hired can explain these concepts in plain English while demonstrating deep understanding of the underlying principles. They don’t just memorize answers—they understand the trade-offs and when to apply each pattern.
If you’re preparing for .NET developer interviews, practice explaining these concepts out loud. The ability to communicate technical ideas clearly is just as important as the technical knowledge itself.
And if you want to experiment with any of these concepts, LINQPad is perfect for quickly testing code snippets and seeing how different approaches work in practice. It’s my go-to tool for exploring .NET concepts during interviews and development.