Interfaces & Abstract Classes

17 questions found

How does explicit interface implementation work, and when would you use it instead of a normal (implicit) implementation?

Intermediate
Explicit implementation (`void IShape.Draw()`) makes the member ONLY accessible through a variable/reference TYPED AS THE INTERFACE, not directly on the concrete class instance — useful when a class implements TWO interfaces with a CONFLICTING member signature, or when you want to intentionally hide an interface member from the class's normal public surface.
public interface IEnglishGreeting { string Greet(); }
public interface ISpanishGreeting { string Greet(); }
public class Greeter : IEnglishGreeting, ISpanishGreeting {
  string IEnglishGreeting.Greet() => "Hello";
  string ISpanishGreeting.Greet() => "Hola";
}
Greeter g = new Greeter();
// g.Greet(); // Error: not accessible directly
string hello = ((IEnglishGreeting)g).Greet(); // must cast to access it
Real-world example Resolving a naming conflict when a class needs to implement two interfaces that happen to declare a method with the identical signature.

Common follow-ups: Why can't you simply implement BOTH interfaces' identically-named methods normally (implicitly) at the same time?

OOP

How do static abstract interface members (C# 11+) enable generic math and other 'static polymorphism' patterns?

Advanced
Interfaces can now declare 'static abstract' members (like operators or factory methods) that IMPLEMENTING TYPES must provide as their own static members — this lets generic code constrained to such an interface call STATIC operations (like T.Zero, or the + operator) on the generic type parameter itself, something previously impossible since static members couldn't be part of a traditional interface contract.
public interface IShapeFactory<TSelf> where TSelf : IShapeFactory<TSelf> {
  static abstract TSelf CreateDefault();
}
public class Circle : IShapeFactory<Circle> {
  public static Circle CreateDefault() => new Circle { Radius = 1.0 };
  public double Radius { get; set; }
}
T CreateShape<T>() where T : IShapeFactory<T> => T.CreateDefault(); // calls the STATIC method generically
Real-world example Enabling .NET's own generic math interfaces (INumber<T>, IAdditionOperators<T,T,T>) which rely entirely on static abstract members.

Common follow-ups: Why couldn't C# achieve this same 'call a static method generically through a constraint' pattern before static abstract interface members existed?

Generics

How does interface segregation (the 'I' in SOLID) guide splitting a large, monolithic interface into several smaller, more focused ones?

Advanced
The Interface Segregation Principle states that clients shouldn't be forced to depend on methods they don't actually use — a large interface with many unrelated members should be SPLIT into several smaller, cohesive interfaces, letting each implementing class (and each consumer) depend only on the specific capabilities it genuinely needs.
// Before: monolithic, forces unrelated dependencies
public interface IWorker { void Work(); void Eat(); void Sleep(); }

// After: segregated into focused interfaces
public interface IWorkable { void Work(); }
public interface IFeedable { void Eat(); }
public class Robot : IWorkable { public void Work() { } } // doesn't need Eat/Sleep at all
Real-world example Refactoring a bloated 'god interface' that forces every implementer to stub out methods they don't actually need.

Common follow-ups: How does a segregated interface design specifically improve testability compared to one large interface?

Design Patterns in C#

How would you design a class hierarchy combining an abstract base class WITH multiple interfaces to model both shared implementation AND multiple independent capabilities?

Advanced
Combine ONE abstract base class (providing shared state/implementation for the core 'is-a' relationship) with MULTIPLE interfaces (each expressing an independent 'can-do' capability) — a class can extend exactly one abstract class while freely implementing as many interfaces as it genuinely needs, giving you the benefits of both approaches together.
public abstract class Vehicle {
  public string Model { get; set; } = "";
  public abstract void Start();
}
public interface IElectric { int BatteryLevel { get; } }
public interface IAutonomous { void EngageAutopilot(); }

public class Tesla : Vehicle, IElectric, IAutonomous {
  public override void Start() { }
  public int BatteryLevel { get; set; }
  public void EngageAutopilot() { }
}
Real-world example Modeling a Tesla car that shares core Vehicle behavior AND independently implements electric and autonomous-driving capabilities.

Common follow-ups: In what order must a class list its base class versus its implemented interfaces in the declaration?

Records & Pattern Matching

How does the 'sealed' modifier interact with abstract classes and interface method overrides to control further extensibility?

Advanced
'sealed' on a class prevents further inheritance entirely; on an OVERRIDING method (`public sealed override`), it prevents any FURTHER derived class from overriding that specific method again, even though the class itself remains inheritable — useful for locking down a critical piece of behavior in an otherwise still-extensible class hierarchy.
public abstract class Shape {
  public abstract double Area();
}
public class Circle : Shape {
  public sealed override double Area() => Math.PI * Radius * Radius; // no further overriding allowed
  public double Radius { get; set; }
}
// public class SpecialCircle : Circle { public override double Area() { } } // Error: Area is sealed
Real-world example Locking down a security-critical or invariant-preserving method so no further subclass can accidentally break its guaranteed behavior.

Common follow-ups: Why would a library author specifically choose to seal ONE method rather than sealing the entire class?

OOP

How would you implement the 'Liskov Substitution Principle' correctly when designing an abstract class hierarchy, and what's a classic violation example?

Advanced
LSP requires that any subclass must be fully usable anywhere its base class is expected, WITHOUT breaking the caller's expectations — a classic violation is a 'Square extends Rectangle' hierarchy where setting Square's Width also changes its Height (to stay square), silently breaking code that assumes setting Rectangle.Width leaves Height unaffected.
public class Rectangle {
  public virtual double Width { get; set; }
  public virtual double Height { get; set; }
}
public class Square : Rectangle {
  public override double Width { get => base.Width; set { base.Width = value; base.Height = value; } } // LSP violation!
}
// Code assuming 'rect.Width = 5' doesn't affect Height breaks silently for a Square
Real-world example Recognizing and avoiding a classic LSP violation when a seemingly natural 'is-a' relationship (Square is-a Rectangle) breaks behavioral expectations.

Common follow-ups: What's a better design that avoids this specific Square/Rectangle LSP trap entirely?

Design Patterns in C#

What is the difference between an interface and an abstract class in C#, and when should you choose one over the other?

Beginner
An interface defines a pure contract (historically method signatures only, though default interface methods exist since C# 8) with no fields or constructors, and a class can implement any number of interfaces simultaneously -- an abstract class can mix abstract (unimplemented) and concrete (implemented) members, can hold fields, properties, and constructors, and provides genuinely shared behavior to its subclasses, but a class can inherit from only one. Use an interface to enforce a capability across otherwise-unrelated classes (like IComparable), and an abstract class when a family of closely related classes should share real, common implementation.
interface IAnimal { void MakeSound(); } // pure contract, no implementation

abstract class Animal {
    public abstract void MakeSound();       // must be implemented by subclasses
    public void Sleep() => Console.WriteLine("Sleeping..."); // shared, concrete behavior
}

class Dog : Animal, IAnimal {
    public override void MakeSound() => Console.WriteLine("Bark!");
}
Real-world example A shape-drawing library defines an IDrawable interface implemented by many unrelated classes (Circle, Chart, Icon), while a closely-related Shape abstract class provides shared Area()/Perimeter() scaffolding specifically for its own geometric subclasses, illustrating both tools used for their distinct, complementary purposes in the same codebase.

Common follow-ups: How do default interface methods (C# 8+) blur this traditional distinction?;What specifically breaks if two interfaces a class implements both declare conflicting default methods?

Interfaces & Abstract Classes;OOP

Showing 11–17 of 17