TL;DR

  • Use override for polymorphism and consistent behavior across base and derived classes.
  • Use new only for method hiding when you explicitly want different behavior based on reference type.
  • Default to override unless you’re interfacing with legacy code or deliberately breaking substitution.

In C#, two keywords control how derived classes can redefine methods from their parent classes: override and new. While they may seem to serve similar purposes, they operate on fundamentally different principles that affect method resolution, polymorphism, and code maintainability.

Understanding Method Resolution

The difference between override and new comes down to method resolution - how C# determines which method implementation to call at runtime:

  • override: Uses dynamic dispatch - the runtime looks at the actual object type
  • new: Uses static binding - the compiler looks at the reference type

This distinction is crucial for understanding polymorphic behavior in inheritance hierarchies.

The Technical Details

Method Overriding with override

When you use the override keyword:

  1. The base method must be marked virtual, abstract, or override
  2. The method signature must match exactly (name, parameters, return type)
  3. The access modifier must be the same or less restrictive
  4. The Virtual Method Table (VMT) is updated to point to the new implementation
public class Base
{
    public virtual void Display() => Console.WriteLine("Base class");
}

public class Derived : Base
{
    public override void Display() => Console.WriteLine("Derived class");
}

// The VMT ensures the correct method is called based on object type
Base obj = new Derived();
obj.Display();  // Output: "Derived class"

Method Hiding with new

When you use the new keyword:

  1. The base method doesn’t need any special modifier
  2. The method signature can differ (though usually kept the same for clarity)
  3. The base method remains unchanged in the VMT
  4. The derived method is only called when the reference type matches
public class Base
{
    public void Process() => Console.WriteLine("Base processing");
}

public class Derived : Base
{
    public new void Process() => Console.WriteLine("Derived processing");
}

Derived d = new Derived();
d.Process();  // Output: "Derived processing"

Base b = d;   // Same object, different reference type
b.Process();  // Output: "Base processing"

When to Use Each Keyword

Use override WhenUse new When
You want to extend or refine base class behaviorThe base method isn’t virtual and can’t be changed
You need consistent behavior regardless of reference typeYou need to completely replace functionality for a specific derived type
You’re implementing an interface or abstract methodYou’re integrating with legacy code that can’t be modified
You want to maintain the IS-A relationship principleYou want to deliberately break the Liskov Substitution Principle

Real-World Gotchas

The new keyword often leads to subtle bugs when developers misunderstand its behavior:

public class ReportGenerator
{
    public virtual void GenerateReport() => Console.WriteLine("Basic report");
}

public class PDFReportGenerator : ReportGenerator
{
    // Dangerous! This doesn't override!
    public new void GenerateReport() => Console.WriteLine("PDF report");
}

// Later in your application...
ReportGenerator report = GetReportGenerator(); // Returns a PDFReportGenerator
report.GenerateReport(); // Still outputs "Basic report" - not what was expected!

Advanced Considerations

  • Performance: override is slightly slower due to virtual method calls, but this difference is negligible in most applications.
  • Base Access: Both allow calling the base method with base.Method()
  • Compiler Warnings: C# will warn about unintentional hiding without new
  • Sealed Methods: Use sealed override to prevent further overriding

Best Practice Recommendation

In most object-oriented designs, prefer override to ensure consistent behavior and proper polymorphism. Use new only when you explicitly want method hiding and fully understand its implications. If you find yourself needing to use new, consider whether your design could be improved by refactoring to avoid method hiding.

Related Posts