Back to Blog
C#

C# override vs new: Choosing the Right Method Behavior

Understand the practical difference between override and new in C#: how each affects polymorphism, virtual dispatch, and when to use it.

C#method overridingmethod hidingpolymorphisminheritancevirtual methods
Diagram showing override and new method behavior in C# inheritance

When you declare a method in a derived class that has the same signature as a method in the base class, C# gives you two choices: override or new. In short, use override when the method should participate in polymorphism; use new only when you intentionally want to hide a base member. The choice changes how the method behaves at runtime and how it interacts with polymorphism. This article explains the practical difference between the two keywords, with code examples and guidance on when to use each.

The Core Difference Between override and new

override extends or replaces a virtual method from the base class, and it participates in polymorphic dispatch. new hides the base method entirely, creating a separate method that is only called when the object is referenced through the derived type. The distinction matters when you call a method through a base-class reference.

Consider this base class:

public class Animal { public virtual void Speak() { Console.WriteLine("Animal speaks"); } }

A derived class can override or hide Speak. The compiler treats these as two different operations, and the runtime behavior differs significantly.

How Virtual Dispatch Works in C#

Virtual dispatch is the mechanism that allows the runtime to call the most derived implementation of a virtual method. When you mark a method as virtual, the runtime uses a vtable (virtual method table) to resolve the call based on the actual type of the object, not the type of the reference.

If a derived class uses override, it replaces the base implementation in the vtable for that specific type. Any call through a base-class reference to that object invokes the override. If the derived class uses new, it does not modify the vtable entry; it creates a completely separate method that is not part of the virtual dispatch chain.

Using override to Extend Base Class Behavior

When you use override, you are explicitly stating that the derived method is the implementation that should be called polymorphically. The base method must be marked virtual, abstract, or override (and not be sealed). The signature must match exactly, and the overriding method must have the same accessibility as the base method.

public class Dog : Animal { public override void Speak() { Console.WriteLine("Dog barks"); } }

Now, whether you call Speak through an Animal reference or a Dog reference, the output is always "Dog barks". This is the expected behavior for most inheritance scenarios where you want derived types to provide specialized behavior while keeping a common interface.

Using new to Hide a Base Class Method

The new keyword in a method declaration hides the base method. It does not require the base method to be virtual. The derived method is independent; it does not override anything. The compiler will issue a warning if you hide a method without using new, but the behavior is the same.

public class Cat : Animal { public new void Speak() { Console.WriteLine("Cat meows"); } }

If you call Speak on a Cat reference, you get "Cat meows". But if you assign a Cat instance to an Animal variable and call Speak, the runtime uses virtual dispatch and finds no override, so it calls the base Animal.Speak and outputs "Animal speaks". This is the key difference: new breaks polymorphism.

Runtime Behavior: Which Method Gets Called?

The method that executes depends on whether the call is virtual. For an override, the call is virtual: the runtime looks up the vtable using the actual object type and calls the most derived implementation. For a new method that is not itself declared virtual, the compiler resolves the call by the static type of the reference.

Animal animal = new Dog(); animal.Speak(); // Dog barks (override) Animal animal2 = new Cat(); animal2.Speak(); // Animal speaks (new hides, no override) Cat cat = new Cat(); cat.Speak(); // Cat meows (new method)

This behavior is consistent with the C# specification. The override keyword is the only way for a derived-class method to replace the inherited virtual method in the same dispatch chain. The new keyword is a compile-time directive that tells the compiler the hiding is intentional and suppresses the warning; it does not add the method to the existing virtual dispatch chain.

Common Pitfalls and How to Avoid Them

The most common mistake is using new when you intend polymorphic behavior. This often happens when a developer adds a method with the same name as a base method but forgets to mark the base method as virtual. The result is that calls through base-class references silently invoke the base implementation, which can lead to subtle bugs.

Another pitfall is mixing override and new in a long inheritance chain. If an intermediate class uses an accessible new method to hide a virtual method, the original virtual chain is broken for types below it. A further derived class can only override the hiding method if that new method was declared virtual; if it was not, the compiler rejects a later override. Even when a later override compiles, calls through a reference to the original base class do not reach it, because the overriding method belongs to the new method, not the original virtual method. This can create confusing behavior if you are not careful about the exact types in the call chain.

To avoid these issues, always ask whether the method should be polymorphic. If it should, mark the base method virtual and use override. If you are intentionally providing a non-polymorphic alternative, use new and document why.

Choosing Between override and new in Real Code

Use override when you want derived classes to provide a specialized implementation that is callable through a base interface. This is the standard pattern for frameworks, plugins, and any design that relies on polymorphism.

Use new when you need to add a method with the same name as a base method but you do not want it to participate in virtual dispatch. This is rare and usually indicates a design issue. For example, if you are extending a class whose base method is not virtual, new lets you define a method with the same signature and suppress the compiler warning. But you should consider renaming the method to avoid confusion.

A practical guideline: if you find yourself using new frequently, reconsider the inheritance hierarchy. It may be better to use composition or to redesign the base class so that the method is virtual.

Compatibility and Maintainability Considerations

The choice between override and new has long-term maintainability implications. override preserves the contract of the base class and ensures that derived types behave consistently when used polymorphically. new can break that contract and cause unexpected behavior for consumers who hold a base-class reference.

When you change a base method from non-virtual to virtual, existing new methods in derived classes do not automatically become overrides. They continue to hide the base method, and the compiler will not warn you. If a later subclass tries to use override and the intermediate new method is not virtual, the compiler will reject the attempt. To maintain clarity, always document the intent of each method that uses new, and consider adding a comment explaining why hiding is necessary.

From a runtime perspective, an override adds virtual dispatch through a vtable lookup, which is a negligible cost in most applications. A non-virtual new method is called directly, but the performance difference is not significant enough to drive the decision. The primary factor should be the semantic correctness of the design, not micro-optimization.

In production code, the most reliable approach is to avoid new unless you have a concrete reason that cannot be solved with a different method name. When you do use it, make sure the hiding behavior is intentional and well understood by the entire team. Prefer override for any method that represents a behavior that should be replaceable by derived types.

C# override vs new: Practical Usage and Code Examples | RYUSLOG DEV