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 typenew
: 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:
- The base method must be marked
virtual
,abstract
, oroverride
- The method signature must match exactly (name, parameters, return type)
- The access modifier must be the same or less restrictive
- 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:
- The base method doesn’t need any special modifier
- The method signature can differ (though usually kept the same for clarity)
- The base method remains unchanged in the VMT
- 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 When | Use new When |
---|---|
You want to extend or refine base class behavior | The base method isn’t virtual and can’t be changed |
You need consistent behavior regardless of reference type | You need to completely replace functionality for a specific derived type |
You’re implementing an interface or abstract method | You’re integrating with legacy code that can’t be modified |
You want to maintain the IS-A relationship principle | You 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
- Method Overriding in C#: What It Is, Why It Matters, and How to Change Parent Behavior
- Polymorphism in C#: How Template Method, Strategy, and Visitor Patterns Make Your Code Flexible
- When Inheritance Still Makes Sense in C#: Polymorphism Without Swapping
- What Is Method Overloading in C# and Why Should You Use It?
- How Polymorphism Makes C# Code Flexible: Real-World Examples and Best Practices