C optional parameters on overridden methods
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Optional parameters and method overriding look compatible in C#, but they interact in a way that surprises many developers. The key rule is that the default argument value is chosen at compile time from the static type of the reference, not from the runtime type of the object.
That means an override can change behavior in the method body, but it does not change which optional default gets substituted at the call site. If you miss that rule, virtual dispatch and default arguments appear to disagree with each other.
Why Optional Parameters Behave This Way
In C#, optional arguments are not dynamically looked up at runtime. The compiler inserts the default value into the call based on the method signature visible at compile time.
Consider this example:
The override runs in both cases, but the default value used for a.Print() comes from BasePrinter, because the compiler sees a as a BasePrinter. The default value for b.Print() comes from DerivedPrinter.
So the output reflects both compile-time binding of optional arguments and runtime virtual dispatch of the method body.
Why This Can Be Confusing
Most developers expect overriding to behave entirely at runtime. That expectation is reasonable for ordinary virtual dispatch, but optional arguments are different because they are partly a call-site feature.
The compiler effectively rewrites the call to include the missing argument. Once that happens, the overridden method simply receives an explicit value.
That is why this topic is less about whether overrides are allowed and more about whether changing default values on virtual methods is a good idea. Usually it is not.
A Safer Design
The safest approach is to avoid optional parameters on virtual or abstract methods when the default value is part of the API contract. Instead, use overloads:
Now the default value lives in one non-virtual entry point, and the polymorphic part is separated into the core method. That design is easier to reason about.
When Keeping Optional Parameters Is Acceptable
If a virtual method already has an optional parameter, the least surprising choice is to keep the same default value in the override. That does not change how compile-time binding works, but it reduces inconsistency between reference types.
In other words, the feature is legal, but changing the default value in the override is what creates confusion.
Common Pitfalls
The most common mistake is assuming the override's default value will always be used. It will not if the call is compiled against the base type.
Another mistake is treating optional parameters as if they were part of runtime polymorphism. They are resolved before virtual dispatch happens.
A third issue is exposing virtual methods with optional parameters in public APIs and later changing the default value. Existing callers may keep the old default because it was compiled into their call sites.
Summary
- Optional argument values in C# are chosen at compile time from the static type.
- Overridden methods still use virtual dispatch for the method body.
- Changing the default value in an override is legal but often confusing.
- Overloads plus a virtual core method are usually a cleaner design.
- If you keep optional parameters on virtual methods, avoid changing their defaults across the hierarchy.

