Method hiding: new
In the previous lesson, a derived class rewrote a method that the base class had marked with the word virtual. What happens if there is no virtual, yet the derived class declares a method with the same name and the same parameters?
Picture a fleet with the instruction "how to say who you are" on the shared board, and nobody may rewrite it. The car drivers put a leaflet with the same title into their own folder. Whoever looks for the instruction on the shared board reads the shared one. Whoever opens the cars' folder reads the leaflet. What gets read depends on where you looked.
Car car = new Car();
Vehicle v = car;
Console.WriteLine(car.Who()); // car
Console.WriteLine(v.Who()); // vehicle
class Vehicle
{
public string Who() => "vehicle";
}
class Car : Vehicle
{
public new string Who() => "car";
}Let's walk through it line by line:
Car car = new Car();creates oneCarobject.Vehicle v = car;gives the same object a second name: the variablevof typeVehicle.car.Who()looks for the method in the typeCarand finds its own version there: it printscar.v.Who()looks for the method in the typeVehicleand finds the base version: it printsvehicle.
One and the same object answered in two ways, because the variable's type picked the version.
Hiding and the new modifier
The method Who in Car does not override the method of Vehicle; it hides it. Hiding is declaring a method in a derived class with the same name and the same parameters as a method of the base class, without override. The base method has not gone anywhere: any code that sees the object through the type Vehicle calls it. A method with the same name but other parameters hides nothing: it is an overload.
The new modifier in the declaration public new string Who() tells the compiler the hiding is intended. Remove new, and the program still compiles and prints the same, but with a warning:
warning CS0108: 'Car.Who()' hides inherited member 'Vehicle.Who()'. Use the new keyword if hiding was intended.The compiler suspects that the same name turned up by accident. new clears that suspicion and changes nothing else. Do not confuse this modifier with new in the expression new Car(): the word is the same, but the meaning differs.
Here the board analogy is off. In the fleet, the reader decides where to look. In a program, the compiler makes the choice before the program runs, and it looks only at the variable's type.
override or new
How does override differ from new? This is a classic interview question. Let's look at both modifiers in one program:
Vehicle truck = new Truck();
Bike bike = new Bike();
Vehicle b = bike;
Console.WriteLine(truck.Who()); // truck
Console.WriteLine(b.Who()); // vehicle
Console.WriteLine(bike.Who()); // bike
class Vehicle
{
public virtual string Who() => "vehicle";
}
class Truck : Vehicle { public override string Who() => "truck"; }
class Bike : Vehicle { public new string Who() => "bike"; }Let's go through the three calls:
truck.Who()printstruck:Truckoverrode the virtual method, and the object picks the version.b.Who()printsvehicle:Bikehid the method, so through a variable of typeVehiclethe base version runs.bike.Who()printsbike: the variable has typeBike, and the version fromBikeis visible.
Here is the difference in a table:
override | new | |
|---|---|---|
| What the base method needs | virtual | nothing |
| What picks the version | the object's type, at run time | the variable's type, at compile time |
| A call through a base-type variable | the derived class's version | the base class's version |
Methods are usually overridden, and hiding is rare. Accidental hiding, however, is a common mistake.
Common mistake
While overriding ToString, someone forgot to write override:
var bike = new Bike();
Console.WriteLine(bike); // Bike
class Bike
{
public string ToString() => "my bike"; // ✗
}warning CS0114: 'Bike.ToString()' hides inherited member 'object.ToString()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.The program compiles and prints Bike, not my bike. Without override, the method ToString in Bike hid the virtual ToString of object instead of overriding it. Console.WriteLine takes the object as an object and so calls the version of object, which returns the type's name. Write public override string ToString(), and the program prints my bike.
Key points
- A method with the same name and parameters but no
overridehides the base class's method; thenewmodifier says this is intended and removes the warningCS0108. - With hiding, the variable's type picks the version; with overriding, the object's type does.
- A method declared with
newis not visible through a base-type variable: the base class's version runs. - A forgotten
overrideturns overriding into hiding, and the compiler warns withCS0114.