Knowing When to Use Override and New Keywords (C# Programming Guide)
In C#, a method in a derived class can have the same name as a method in the base class. You can specify how the methods interact by using the new and override keywords. The override
modifier extends the base class virtual
method, and the new
modifier hides an accessible base class method. The difference is illustrated in the examples in this topic.
In a console application, declare the following two classes, BaseClass
and DerivedClass
. DerivedClass
inherits from BaseClass
.
class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}
class DerivedClass : BaseClass
{
public void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
In the Main
method, declare variables bc
, dc
, and bcdc
.
bc
is of typeBaseClass
, and its value is of typeBaseClass
.dc
is of typeDerivedClass
, and its value is of typeDerivedClass
.bcdc
is of typeBaseClass
, and its value is of typeDerivedClass
. This is the variable to pay attention to.
Because bc
and bcdc
have type BaseClass
, they can only directly access Method1
, unless you use casting. Variable dc
can access both Method1
and Method2
. These relationships are shown in the following code.
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
bc.Method1();
dc.Method1();
dc.Method2();
bcdc.Method1();
}
// Output:
// Base - Method1
// Base - Method1
// Derived - Method2
// Base - Method1
}
Next, add the following Method2
method to BaseClass
. The signature of this method matches the signature of the Method2
method in DerivedClass
.
public void Method2()
{
Console.WriteLine("Base - Method2");
}
Because BaseClass
now has a Method2
method, a second calling statement can be added for BaseClass
variables bc
and bcdc
, as shown in the following code.
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
When you build the project, you see that the addition of the Method2
method in BaseClass
causes a warning. The warning says that the Method2
method in DerivedClass
hides the Method2
method in BaseClass
. You are advised to use the new
keyword in the Method2
definition if you intend to cause that result. Alternatively, you could rename one of the Method2
methods to resolve the warning, but that is not always practical.
Before adding new
, run the program to see the output produced by the additional calling statements. The following results are displayed.
// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2
The new
keyword preserves the relationships that produce that output, but it suppresses the warning. The variables that have type BaseClass
continue to access the members of BaseClass
, and the variable that has type DerivedClass
continues to access members in DerivedClass
first, and then to consider members inherited from BaseClass
.
To suppress the warning, add the new
modifier to the definition of Method2
in DerivedClass
, as shown in the following code. The modifier can be added before or after public
.
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
Run the program again to verify that the output has not changed. Also verify that the warning no longer appears. By using new
, you are asserting that you are aware that the member that it modifies hides a member that is inherited from the base class. For more information about name hiding through inheritance, see new Modifier.
To contrast this behavior to the effects of using override
, add the following method to DerivedClass
. The override
modifier can be added before or after public
.
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
Add the virtual
modifier to the definition of Method1
in BaseClass
. The virtual
modifier can be added before or after public
.
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
Run the project again. Notice especially the last two lines of the following output.
// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2
The use of the override
modifier enables bcdc
to access the Method1
method that is defined in DerivedClass
. Typically, that is the desired behavior in inheritance hierarchies. You want objects that have values that are created from the derived class to use the methods that are defined in the derived class. You achieve that behavior by using override
to extend the base class method.
The following code contains the full example.
using System;
using System.Text;
namespace OverrideAndNew
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
// The following two calls do what you would expect. They call
// the methods that are defined in BaseClass.
bc.Method1();
bc.Method2();
// Output:
// Base - Method1
// Base - Method2
// The following two calls do what you would expect. They call
// the methods that are defined in DerivedClass.
dc.Method1();
dc.Method2();
// Output:
// Derived - Method1
// Derived - Method2
// The following two calls produce different results, depending
// on whether override (Method1) or new (Method2) is used.
bcdc.Method1();
bcdc.Method2();
// Output:
// Derived - Method1
// Base - Method2
}
}
class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
public virtual void Method2()
{
Console.WriteLine("Base - Method2");
}
}
class DerivedClass : BaseClass
{
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
}
The following example illustrates similar behavior in a different context. The example defines three classes: a base class named Car
and two classes that are derived from it, ConvertibleCar
and Minivan
. The base class contains a DescribeCar
method. The method displays a basic description of a car, and then calls ShowDetails
to provide additional information. Each of the three classes defines a ShowDetails
method. The new
modifier is used to define ShowDetails
in the ConvertibleCar
class. The override
modifier is used to define ShowDetails
in the Minivan
class.
// Define the base class, Car. The class defines two methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is selected, the base class method or the derived class method.
class Car
{
public void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}
public virtual void ShowDetails()
{
System.Console.WriteLine("Standard transportation.");
}
}
// Define the derived classes.
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
// hides the base class method.
class ConvertibleCar : Car
{
public new void ShowDetails()
{
System.Console.WriteLine("A roof that opens up.");
}
}
// Class Minivan uses the override modifier to specify that ShowDetails
// extends the base class method.
class Minivan : Car
{
public override void ShowDetails()
{
System.Console.WriteLine("Carries seven people.");
}
}
The example tests which version of ShowDetails
is called. The following method, TestCars1
, declares an instance of each class, and then calls DescribeCar
on each instance.
public static void TestCars1()
{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");
Car car1 = new Car();
car1.DescribeCar();
System.Console.WriteLine("----------");
// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");
Minivan car3 = new Minivan();
car3.DescribeCar();
System.Console.WriteLine("----------");
}
TestCars1
produces the following output. Notice especially the results for car2
, which probably are not what you expected. The type of the object is ConvertibleCar
, but DescribeCar
does not access the version of ShowDetails
that is defined in the ConvertibleCar
class because that method is declared with the new
modifier, not the override
modifier. As a result, a ConvertibleCar
object displays the same description as a Car
object. Contrast the results for car3
, which is a Minivan
object. In this case, the ShowDetails
method that is declared in the Minivan
class overrides the ShowDetails
method that is declared in the Car
class, and the description that is displayed describes a minivan.
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
TestCars2
creates a list of objects that have type Car
. The values of the objects are instantiated from the Car
, ConvertibleCar
, and Minivan
classes. DescribeCar
is called on each element of the list. The following code shows the definition of TestCars2
.
public static void TestCars2()
{
System.Console.WriteLine("\nTestCars2");
System.Console.WriteLine("----------");
var cars = new List<Car> { new Car(), new ConvertibleCar(),
new Minivan() };
foreach (var car in cars)
{
car.DescribeCar();
System.Console.WriteLine("----------");
}
}
The following output is displayed. Notice that it is the same as the output that is displayed by TestCars1
. The ShowDetails
method of the ConvertibleCar
class is not called, regardless of whether the type of the object is ConvertibleCar
, as in TestCars1
, or Car
, as in TestCars2
. Conversely, car3
calls the ShowDetails
method from the Minivan
class in both cases, whether it has type Minivan
or type Car
.
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
Methods TestCars3
and TestCars4
complete the example. These methods call ShowDetails
directly, first from objects declared to have type ConvertibleCar
and Minivan
(TestCars3
), then from objects declared to have type Car
(TestCars4
). The following code defines these two methods.
public static void TestCars3()
{
System.Console.WriteLine("\nTestCars3");
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
Minivan car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
public static void TestCars4()
{
System.Console.WriteLine("\nTestCars4");
System.Console.WriteLine("----------");
Car car2 = new ConvertibleCar();
Car car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
The methods produce the following output, which corresponds to the results from the first example in this topic.
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
The following code shows the complete project and its output.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OverrideAndNew2
{
class Program
{
static void Main(string[] args)
{
// Declare objects of the derived classes and test which version
// of ShowDetails is run, base or derived.
TestCars1();
// Declare objects of the base class, instantiated with the
// derived classes, and repeat the tests.
TestCars2();
// Declare objects of the derived classes and call ShowDetails
// directly.
TestCars3();
// Declare objects of the base class, instantiated with the
// derived classes, and repeat the tests.
TestCars4();
}
public static void TestCars1()
{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");
Car car1 = new Car();
car1.DescribeCar();
System.Console.WriteLine("----------");
// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");
Minivan car3 = new Minivan();
car3.DescribeCar();
System.Console.WriteLine("----------");
}
// Output:
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
public static void TestCars2()
{
System.Console.WriteLine("\nTestCars2");
System.Console.WriteLine("----------");
var cars = new List<Car> { new Car(), new ConvertibleCar(),
new Minivan() };
foreach (var car in cars)
{
car.DescribeCar();
System.Console.WriteLine("----------");
}
}
// Output:
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
public static void TestCars3()
{
System.Console.WriteLine("\nTestCars3");
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
Minivan car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
// Output:
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
public static void TestCars4()
{
System.Console.WriteLine("\nTestCars4");
System.Console.WriteLine("----------");
Car car2 = new ConvertibleCar();
Car car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
// Output:
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
}
// Define the base class, Car. The class defines two virtual methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is used, the base class method or the derived class method.
class Car
{
public virtual void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}
public virtual void ShowDetails()
{
System.Console.WriteLine("Standard transportation.");
}
}
// Define the derived classes.
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
// hides the base class method.
class ConvertibleCar : Car
{
public new void ShowDetails()
{
System.Console.WriteLine("A roof that opens up.");
}
}
// Class Minivan uses the override modifier to specify that ShowDetails
// extends the base class method.
class Minivan : Car
{
public override void ShowDetails()
{
System.Console.WriteLine("Carries seven people.");
}
}
}