You've learned inheritance, interfaces, abstract classes, and polymorphism. Now face 15 deeply researched interview questions that probe the nuances senior developers are expected to know. Topics include the diamond problem, vtables, SOLID principles, covariant returns, dependency injection, and more.
Take your time. Think like an architect. 🏛️
📋 Instructions
🧠 Quiz Time
0 / 15 answered
1
When should you use an abstract class instead of an interface in C#?
A. When you need multiple inheritance across unrelated types
B. When you need to share common state (fields) and partial implementation among related classes
C. When you want to define only method signatures with no implementation at all
D. When you want to achieve loose coupling between unrelated modules
Abstract classes can contain fields, constructors, and concrete methods — making them ideal for sharing state and partial logic among related classes. Interfaces (pre-C# 8) cannot hold instance state. If your types share an 'is-a' relationship with common data, abstract classes are the right tool.
2
C# does not support multiple class inheritance. How does C# solve the 'diamond problem' that occurs in languages like C++ which allow it?
A. C# allows multiple inheritance but uses virtual base classes automatically
B. C# prevents the problem entirely by allowing single class inheritance only, while permitting multiple interface implementation
C. C# resolves ambiguity at runtime by choosing the first parent in the declaration order
D. C# uses the 'diamond' keyword to specify which parent takes priority
The diamond problem arises when a class inherits from two classes that share a common ancestor, causing ambiguity about which version of a method to use. C# avoids this entirely by restricting classes to single inheritance. Multiple interfaces are allowed because interfaces (traditionally) have no state or implementation, so there is no conflicting inherited logic — and when default methods conflict, the compiler forces you to provide an explicit implementation.
3
What is the virtual method table (vtable) and how does it enable polymorphism in C#?
A. It is a compile-time lookup table that maps method names to their parameter types
B. It is a runtime data structure associated with each type that stores pointers to the actual method implementations, enabling virtual/override dispatch
C. It is a hash table stored in the garbage collector that tracks which methods have been called
D. It is a static dictionary created manually by the developer to route method calls
Each class with virtual methods has a vtable — a runtime table of method pointers. When you call a virtual method through a base reference, the CLR looks up the vtable of the actual object type to find the correct overridden method. This indirection is what makes runtime polymorphism work, at the cost of a small performance overhead compared to non-virtual calls.
4
C# 9 introduced covariant return types. What does this feature allow?
A. A method override can accept a more specific parameter type than the base method
B. A method override can return a more derived (specific) type than the base method's return type
C. A method can return different types at runtime based on the input arguments
D. A generic interface can use the 'in' keyword for return type parameters
Covariant return types (C# 9) allow an overriding method to declare a return type that is more derived than what the base virtual method returns. For example, a base method returning 'Animal' can be overridden to return 'Dog'. This avoids unnecessary casting by the caller and makes APIs more precise. This feature is supported only for class methods (not interfaces).
5
The Liskov Substitution Principle (LSP) states that objects of a base type should be replaceable with objects of a derived type without altering correctness. Which of the following violates LSP?
A. A 'Square' class inheriting from 'Rectangle' where setting Width also changes Height, breaking Rectangle's independent Width/Height contract
B. A 'Dog' class inheriting from 'Animal' and overriding Speak() to return 'Woof'
C. A 'SavingsAccount' class inheriting from 'BankAccount' and adding an interest rate field
D. A 'ElectricCar' class inheriting from 'Car' and overriding StartEngine() to start a motor silently
The classic Square-Rectangle problem is the textbook LSP violation. A Rectangle's contract implies Width and Height can be set independently. A Square that silently couples them breaks callers' assumptions — code that sets Width to 5 and Height to 10 expecting area = 50 would get 100 instead. Subtypes must honor the behavioral contracts of their base types.
6
What is the key difference between `new` (method hiding) and `override` in C#?
A. 'new' creates a brand-new method that participates in polymorphism; 'override' does not
B. 'override' replaces the base virtual method in the vtable enabling runtime polymorphism; 'new' hides the base method and the call depends on the reference type at compile time
C. Both 'new' and 'override' behave identically — the difference is only syntactic
D. 'new' can only be used with abstract methods; 'override' works with any method
With 'override', the derived method replaces the base's vtable entry — calling through a base reference still reaches the derived version (polymorphism). With 'new', the derived method is a separate slot — calling through a base reference invokes the base version, and only calling through the derived type invokes the hiding method. This is why accidental hiding is a common source of bugs.
7
What does the `sealed` keyword do when applied to a class? And when applied to an overridden method?
A. On a class: prevents inheritance. On a method: prevents the method from being called
B. On a class: prevents instantiation. On a method: prevents further overriding in subclasses
C. On a class: prevents inheritance. On a method: prevents further overriding in deeper derived classes
D. On a class: makes it abstract. On a method: makes it non-virtual
A sealed class cannot be used as a base class — no one can inherit from it (e.g., 'string' is sealed). A sealed override stops the override chain — subclasses of the sealing class cannot override that method further, even though it was originally virtual. This is useful to lock down behavior at a specific level of the hierarchy.
8
Two interfaces both define a method `void Execute()`. A class implements both. How does C# resolve this conflict?
A. C# throws a compile error — you cannot implement two interfaces with the same method signature
B. A single implicit implementation satisfies both interfaces; explicit implementation can differentiate behavior per interface
C. The compiler automatically renames one method to avoid the conflict
D. You must use the 'priority' attribute to specify which interface takes precedence
If you write one public `Execute()` method, it implicitly satisfies both interfaces. If you need different behavior per interface, use explicit interface implementation: `void IFirst.Execute() { ... }` and `void ISecond.Execute() { ... }`. Explicit implementations are called through the interface type only, not through the class directly.
9
When is explicit interface implementation preferred over implicit implementation?
A. When you want the method to be publicly accessible on the concrete class at all times
B. When two interfaces define methods with the same signature that need different implementations, or when you want to hide interface methods from the class's public API
C. When you want better runtime performance due to direct dispatch
D. When the interface has only one method and the class has no other members
Explicit implementation serves two purposes: (1) resolving name collisions when multiple interfaces share a method name, and (2) hiding interface methods from the class's public surface — the method is only callable through the interface type. This keeps the class API clean and signals that the method is part of a specific contract, not general-purpose behavior.
10
The principle 'Favor composition over inheritance' is widely recommended. Why?
A. Composition is always faster at runtime than inheritance in C#
B. Composition avoids tight coupling to a parent class, allows behavior to be swapped at runtime, and supports combining capabilities from multiple sources without fragile base class issues
C. Inheritance is deprecated in modern C# versions and will be removed in C# 13
D. Composition eliminates the need for interfaces entirely
Inheritance creates tight coupling — changes to a base class ripple through all descendants (the fragile base class problem). Composition lets you build objects from smaller, independent components. You can swap implementations at runtime (via interfaces), combine behaviors from unrelated sources, and avoid deep inheritance hierarchies. Use inheritance for genuine 'is-a' relationships; use composition for 'has-a' capabilities.
11
Which SOLID principle does this code violate? `class UserService { public void Register(User u) { /* save to DB, send email, log event, charge payment */ } }`
A. Open/Closed Principle (OCP)
B. Liskov Substitution Principle (LSP)
C. Single Responsibility Principle (SRP)
D. Interface Segregation Principle (ISP)
The Single Responsibility Principle says a class should have only one reason to change. This UserService does database work, emailing, logging, and payment — four distinct responsibilities. If the email provider changes, this class changes. If logging format changes, this class changes. Each concern should be extracted into its own class (e.g., IEmailService, IPaymentService) and injected as dependencies.
12
What is the difference between `protected internal` and `private protected` access modifiers in C#?
A. They are synonyms — both mean accessible within the assembly and derived classes
B. 'protected internal' = accessible within the assembly OR derived classes (union); 'private protected' = accessible only within derived classes that are also in the same assembly (intersection)
C. 'protected internal' is accessible only in the same namespace; 'private protected' is accessible only in the same file
D. 'private protected' was removed in C# 10 and is no longer valid
These are two compound access modifiers with subtly different semantics. 'protected internal' is the UNION: accessible by any code in the same assembly OR any derived class (even in other assemblies). 'private protected' (C# 7.2+) is the INTERSECTION: accessible only by derived classes that are also in the same assembly. 'private protected' is more restrictive — useful for library authors who want derived access only within their own assembly.
13
Can interfaces inherit from other interfaces in C#? If so, what happens when a class implements the derived interface?
A. No, interfaces cannot inherit from other interfaces in C#
B. Yes, and the implementing class must implement members from the derived interface only — base interface members are ignored
C. Yes, and the implementing class must implement all members from both the derived and all base interfaces in the chain
D. Yes, but only if the base interface is marked with the 'inheritable' attribute
Interfaces can inherit from one or more interfaces. When a class implements the derived interface, it must provide implementations for all members across the entire interface inheritance chain. For example: `interface IShape { double Area(); }` and `interface I3DShape : IShape { double Volume(); }` — a class implementing I3DShape must implement both Area() and Volume().
14
What are marker interfaces and when are they useful in C#?
A. Interfaces that contain exactly one method for functional programming patterns
B. Empty interfaces (no members) used to 'tag' or categorize classes for runtime type checking or framework behavior
C. Interfaces that are automatically generated by the compiler for anonymous types
D. Interfaces marked with the [Obsolete] attribute to signal deprecation
A marker interface is an interface with no members — `interface ISerializable { }`. Classes implement it purely to signal a capability or category. Code can check `if (obj is ISerializable)` at runtime. While custom attributes have largely replaced marker interfaces in modern C# for tagging purposes, marker interfaces still appear in frameworks and are useful when you need compile-time type constraints via generics: `void Process<T>(T item) where T : ISerializable`.
15
How do interfaces enable Dependency Injection (DI), and why is this important for testable, maintainable code?
A. Interfaces have built-in DI containers that handle object creation automatically
B. Interfaces allow classes to depend on abstractions rather than concrete implementations, so dependencies can be swapped (e.g., mock services in tests) without changing the consumer's code
C. Interfaces generate proxy classes at compile time that intercept all method calls for injection
D. Interfaces prevent any class from being instantiated directly, forcing all creation through factory methods
Dependency Injection follows the Dependency Inversion Principle (the 'D' in SOLID): high-level modules should depend on abstractions, not concretions. By coding against an interface (e.g., IEmailService), you can inject a real SmtpEmailService in production and a MockEmailService in tests — the consumer class never changes. DI containers (like Microsoft.Extensions.DependencyInjection) resolve interface-to-implementation mappings at runtime, enabling loose coupling and easy testability.