39. Method Hiding in C#
Level: Advanced
Goal: Understand the subtle but critical difference betweenoverrideandnewkeywords.
Two inheritance problems:
Base class has GetGrade()
Derived class wants its own GetGrade()
Use override or new?
override: Correct OOP behavior (polymorphism)new: Hides the base method (usually wrong)
Most common interview question.
override- runtime polymorphism, virtual dispatchnew- compile-time method hiding, shadowing- Virtual method resolution - how C# decides which method to call
- Reference type vs actual object type - critical difference
- When to use override (almost always)
- When to use new (rarely, design smell)
- Common gotchas and avoiding hidden bugs
- Interview-ready explanations
Method Resolution Reference
| Aspect | override (recommended) | new (method hiding) |
|---|---|---|
| Base method | Must be virtual or abstract | Can hide any inherited method |
| Which runs | Most derived type (at runtime) | Reference type (at compile-time) |
| Dispatch | Virtual dispatch (late binding) | Static dispatch (early binding) |
| OOP Design | Correct polymorphism | Usually signals a design problem |
| Polymorphic | Works correctly in base-class collections | Can break polymorphism |
| Example | public override void Method() | public new void Method() |
| Use Case | Extend base behavior | Rarely (avoid if possible) |
| Interview | Always mention this | Show understanding of danger |
When You'll Use This in SMS
SMS avoids method hiding:
// Wrong BAD - method hiding (confusing)
public class Person { public virtual void Display() => Console.WriteLine("Person"); }
public class Teacher : Person { public new void Display() => Console.WriteLine("Teacher"); } // Hides!
// OK GOOD - method override (polymorphic)
public class Student : Person
{ public override void Display() => Console.WriteLine("Student"); }
Person person = new Student();
person.Display(); // Calls Student.Display (override)
Method hiding vs override: new keyword, virtual/override, polymorphism, why hiding is dangerous. Video coming soon. Subscribe to NexCoding YouTube for updates.
override - Runtime Polymorphism
When base class method is virtual and derived class uses override - the most derived version ALWAYS runs regardless of reference type.
public class Person
{
public virtual void DisplayInfo()
=> Console.WriteLine($"Person: {GetType().Name}");
}
public class Student : Person
{
public override void DisplayInfo()
=> Console.WriteLine($"Student: Sahasra Kumar | 10th Grade");
}
public class Teacher : Person
{
public override void DisplayInfo()
=> Console.WriteLine($"Teacher: Dr. Mehta | Mathematics");
}
// OVERRIDE - virtual dispatch - runs ACTUAL type's method
Person person = new Student(); // Student stored in Person reference
person.DisplayInfo(); // "Student: Sahasra Kumar | 10th Grade"
// Runtime checks: actual object is Student -> calls Student.DisplayInfo
Person person2 = new Teacher();
person2.DisplayInfo(); // "Teacher: Dr. Mehta | Mathematics"
new - Method Hiding (Compile-Time)
new hides the base class method. Which method runs depends on the reference type, not the actual object.
public class Person
{
public void DisplayInfo() // NOT virtual
=> Console.WriteLine($"Person: {GetType().Name}");
}
public class Student : Person
{
public new void DisplayInfo() // HIDES base method
=> Console.WriteLine($"Student: Sahasra Kumar | 10th Grade");
}
// Method hiding - reference type determines which method runs
Student studentRef = new Student();
studentRef.DisplayInfo(); // "Student: Sahasra Kumar" - Student reference -> Student method
Person personRef = new Student(); // Student stored in Person reference
personRef.DisplayInfo(); // "Person: Student" <- !!!
// Compile-time: reference is Person -> calls Person.DisplayInfo
// Does NOT call Student.DisplayInfo even though object IS a Student
Side-by-Side Comparison
public class SchoolMember
{
public virtual void VirtualMethod() => Console.WriteLine("SchoolMember.Virtual");
public void RegularMethod() => Console.WriteLine("SchoolMember.Regular");
}
public class Student : SchoolMember
{
public override void VirtualMethod() => Console.WriteLine("Student.Override");
public new void RegularMethod() => Console.WriteLine("Student.New (hiding)");
}
SchoolMember member = new Student(); // Student in SchoolMember reference
member.VirtualMethod(); // "Student.Override" <- override wins (runtime dispatch)
member.RegularMethod(); // "SchoolMember.Regular" <- new hides (compile-time, uses ref type)
Student student = new Student();
student.VirtualMethod(); // "Student.Override"
student.RegularMethod(); // "Student.New (hiding)" <- Student ref sees Student method
School Management - Real Scenario
Common Mistakes
Problem: Using new instead of override (breaks polymorphism):
public class Person
{
public virtual void DisplayInfo()
=> Console.WriteLine("Person");
}
public class Student : Person
{
public new void DisplayInfo() // WRONG - hiding, not overriding
=> Console.WriteLine("Student");
}
var people = new List<Person>
{
new Student { },
new Student { }
};
foreach (var person in people)
person.DisplayInfo(); // Always prints "Person" - Student version NEVER called
Fix: Use override when base is virtual:
public class Student : Person
{
public override void DisplayInfo() // CORRECT - runtime polymorphism
=> Console.WriteLine("Student");
}
foreach (var person in people)
person.DisplayInfo(); // Prints "Student" correctly
Problem: Forgetting virtual on base method, then using override:
public class Teacher
{
public void GetSalary() // NOT virtual
=> Console.WriteLine("20000");
}
public class PrincipalTeacher : Teacher
{
public override void GetSalary() // Error - base not virtual
=> Console.WriteLine("50000");
}
Fix: Make base method virtual first:
public class Teacher
{
public virtual void GetSalary() // virtual
=> Console.WriteLine("20000");
}
public class PrincipalTeacher : Teacher
{
public override void GetSalary() // OK
=> Console.WriteLine("50000");
}
Problem: Using new when you meant override in a collection:
public class SchoolMember
{
public virtual void PrintReport()
=> Console.WriteLine("Member");
}
public class Teacher : SchoolMember
{
public new void PrintReport() // Hiding - wrong in a collection
=> Console.WriteLine("Teacher Report");
}
var staff = new List<SchoolMember> { new Teacher() };
staff[0].PrintReport(); // Prints "Member" - not "Teacher Report"
Fix: Always use override for polymorphic methods:
public class Teacher : SchoolMember
{
public override void PrintReport() // Correct
=> Console.WriteLine("Teacher Report");
}
staff[0].PrintReport(); // Now prints "Teacher Report"
Problem: Hiding a method and then calling through base reference (confusing):
var teacher = new Teacher();
teacher.PrintReport(); // Teacher version (reference is Teacher)
SchoolMember member = teacher;
member.PrintReport(); // Base version (reference is SchoolMember) - unexpected!
Fix: Consistent behavior - use override:
public class Teacher : SchoolMember
{
public override void PrintReport() // Always called on Teacher objects
=> Console.WriteLine("Teacher");
}
teacher.PrintReport(); // Teacher version
member.PrintReport(); // Teacher version (correct!)
Best Practices
- Use
overrideby default - 99% of the time, this is what you want - Mark methods
virtualintentionally - Not every method should be overridable - Never use
newto hide methods - If you must, it signals design problem - Test polymorphic behavior in collections - Verify correct method runs on each type
- Use
abstractfor must-override methods - Force derived classes to implement - Document virtual methods clearly - Explain what subclasses should do
- Call
base.MethodName()when extending - Combine base + derived behavior - Avoid
newwith virtual methods - Confusing and breaks polymorphism - Keep method signatures identical - Same parameters, return type as base
- Use compiler warnings - Enable warnings for hiding base methods
- Design for inheritance - Virtual methods signal extension points
- Prefer composition over complex inheritance - Simplify polymorphic scenarios
override: Base method must be virtual. Derived version ALWAYS runs regardless of reference type. Runtime polymorphism - late binding.
new: Hides base method. Which version runs depends on reference type, not actual object type. Compile-time dispatch - early binding.
// override - actual type decides
Person p = new Student();
p.DisplayInfo(); // Student version (actual type = Student)
// new - reference type decides
SchoolMember m = new Teacher();
m.PrintCard(); // Base version (reference type = SchoolMember)
Rule: override for true polymorphism, new is a code smell.
When you store Student in Person reference, the compiler uses the reference type (Person) to determine which method to call.
With new (hiding): Calls base Person method.
With override: Calls derived Student method (correct).
var people = new List<Person> { new Student(), new Teacher() };
foreach (var p in people)
p.DisplayInfo(); // With override: correct Student/Teacher methods
// With new: always base Person method (wrong!)
override fixes this - runtime checks actual object type.
Very rarely. Only when:
- Base class has non-virtual method you can't modify
- You must provide different implementation in derived class
- You accept breaking polymorphism (usually wrong decision)
// Legacy code - you can't change Person class
public class Person { public void LegacyMethod() { } } // NOT virtual
public class Student : Person
{
public new void LegacyMethod() { } // Only choice if base not virtual
}
Better solution: Either make base virtual, or use composition instead of inheritance.
new signals design problem - refactor instead.
Compiler error: "cannot override member that is not marked virtual, abstract, or override."
public class Base
{
public void Method() { } // NOT virtual
}
public class Derived : Base
{
public override void Method() { } // Error
}
Solution: Add virtual to base method.
public class Base
{
public virtual void Method() { } // Now override works
}
Compiler enforces correct OOP.
Use base.MethodName() to access base implementation. Useful for extending behavior.
public class Student : Person
{
public override void DisplayInfo()
{
base.DisplayInfo(); // Call Person.DisplayInfo
Console.WriteLine("Student-specific info");
}
}
var s = new Student { Name = "Sahasra" };
s.DisplayInfo();
// Output: Person: Sahasra
// Student-specific info
base lets you combine base + derived behavior.
new: Hides method, compile-time dispatch.
override: Runtime dispatch, calls actual type's implementation.
abstract: Forces derived classes to implement the method.
// abstract - must override
public abstract class Shape
{
public abstract void Draw(); // Every Shape must implement
}
public class Circle : Shape
{
public override void Draw() => Console.WriteLine("Circle");
}
// Usage - polymorphism guaranteed
Shape s = new Circle();
s.Draw(); // Circle version (always works with override)
Abstract + override = correct polymorphism. Best practice.
Use ChatGPT, Claude, or Copilot to go deeper on C# method hiding new keyword vs override. Try these prompts:
"What is the difference between method hiding (new) and method overriding (override) in C#?""If I use new to hide a method, what happens when I call it through a base class reference?""Why would a developer use method hiding instead of override in C#?""Quiz me: what gets printed in this method hiding vs override scenario?"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.