Skip to main content
Updated links (link [4] was dead). Other minor improvements.
Source Link

Since you asked why C# did it this way, it's best to ask the C# creators. Anders Hejlsberg, the lead architect for C#, answered why they chose not to go with virtual by default (as in Java) in an interviewinterview, pertinent snippets are below.

Keep in mind that Java has virtual by default with the finalfinal keyword to mark a method as non-virtual. Still two concepts to learn, but many folks do not know about the final keyword or don't use it proactively. C# forces one to use virtual and new/override to consciously make those decisions.

This would be when a derived class wants to declare that it does not abide by the contract of the base class, but has a method with the same name. (For anyone who doesn't know the difference between new and override in C#, see this MSDN pageMicrosoft Docs page).

  • You created an API, which has a class called Vehicle.

    You created an API, which has a class called Vehicle.

  • I started using your API and derived Vehicle.

    I started using your API and derived Vehicle.

  • Your Vehicle class did not have any method PerformEngineCheck().

    Your Vehicle class did not have any method PerformEngineCheck().

  • In my Car class, I add a method PerformEngineCheck().

    In my Car class, I add a method PerformEngineCheck().

  • You released a new version of your API and added a PerformEngineCheck().

    You released a new version of your API and added a PerformEngineCheck().

  • I cannot rename my method because my clients are dependent on my API, and it would break them.

    I cannot rename my method because my clients are dependent on my API, and it would break them.

  • So when I recompile against your new API, C# warns me of this issue, e.g.

    So when I recompile against your new API, C# warns me of this issue, e.g.

    If the base PerformEngineCheck() was not virtual:

     app2.cs(15,17): warning CS0108: 'Car.PerformEngineCheck()' hides inherited member 'Vehicle.PerformEngineCheck()'.
     Use the new keyword if hiding was intended.
    

    And if the base PerformEngineCheck() was virtual:

     app2.cs(15,17): warning CS0114: 'Car.PerformEngineCheck()' hides inherited member 'Vehicle.PerformEngineCheck()'.
     To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
    

If the base PerformEngineCheck() was not virtual:

<!-- language: none -->

    app2.cs(15,17): warning CS0108: 'Car.PerformEngineCheck()' hides inherited member 'Vehicle.PerformEngineCheck()'.
    Use the new keyword if hiding was intended.

And if the base PerformEngineCheck() was virtual:

<!-- language: none -->

    app2.cs(15,17): warning CS0114: 'Car.PerformEngineCheck()' hides inherited member 'Vehicle.PerformEngineCheck()'.
    To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
  • Now, I must explicitly make a decision whether my class is actually extending the base class' contract, or if it is a different contract but happens to be the same name.

    Now, I must explicitly make a decision whether my class is actually extending the base class' contract, or if it is a different contract but happens to be the same name.

  • By making it new, I do not break my clients if the functionality of the base method was different from the derived method. Any code that referenced Vehicle will not see Car.PerformEngineCheck() called, but code that had a reference to Car will continue to see the same functionality that I had offered in PerformEngineCheck().

    By making it new, I do not break my clients if the functionality of the base method was different from the derived method. Any code that referenced Vehicle will not see Car.PerformEngineCheck() called, but code that had a reference to Car will continue to see the same functionality that I had offered in PerformEngineCheck().

EDIT: While going through the comments, I also came across a write-up by Eric Lippertwrite-up by Eric Lippert (then one of the members of C# design committee) on other example scenarios (mentioned by Brian).

Since you asked why C# did it this way, it's best to ask the C# creators. Anders Hejlsberg, the lead architect for C#, answered why they chose not to go with virtual by default (as in Java) in an interview, pertinent snippets are below.

Keep in mind that Java has virtual by default with the final keyword to mark a method as non-virtual. Still two concepts to learn, but many folks do not know about the final keyword or don't use proactively. C# forces one to use virtual and new/override to consciously make those decisions.

This would be when a derived class wants to declare that it does not abide by the contract of the base class, but has a method with the same name. (For anyone who doesn't know the difference between new and override in C#, see this MSDN page).

  • You created an API, which has a class called Vehicle.
  • I started using your API and derived Vehicle.
  • Your Vehicle class did not have any method PerformEngineCheck().
  • In my Car class, I add a method PerformEngineCheck().
  • You released a new version of your API and added a PerformEngineCheck().
  • I cannot rename my method because my clients are dependent on my API, and it would break them.
  • So when I recompile against your new API, C# warns me of this issue, e.g.

If the base PerformEngineCheck() was not virtual:

<!-- language: none -->

    app2.cs(15,17): warning CS0108: 'Car.PerformEngineCheck()' hides inherited member 'Vehicle.PerformEngineCheck()'.
    Use the new keyword if hiding was intended.

And if the base PerformEngineCheck() was virtual:

<!-- language: none -->

    app2.cs(15,17): warning CS0114: 'Car.PerformEngineCheck()' hides inherited member 'Vehicle.PerformEngineCheck()'.
    To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
  • Now, I must explicitly make a decision whether my class is actually extending the base class' contract, or if it is a different contract but happens to be the same name.
  • By making it new, I do not break my clients if the functionality of the base method was different from the derived method. Any code that referenced Vehicle will not see Car.PerformEngineCheck() called, but code that had a reference to Car will continue to see the same functionality that I had offered in PerformEngineCheck().

EDIT: While going through the comments, I also came across a write-up by Eric Lippert (then one of the members of C# design committee) on other example scenarios (mentioned by Brian).

Since you asked why C# did it this way, it's best to ask the C# creators. Anders Hejlsberg, the lead architect for C#, answered why they chose not to go with virtual by default (as in Java) in an interview, pertinent snippets are below.

Keep in mind that Java has virtual by default with the final keyword to mark a method as non-virtual. Still two concepts to learn, but many folks do not know about the final keyword or don't use it proactively. C# forces one to use virtual and new/override to consciously make those decisions.

This would be when a derived class wants to declare that it does not abide by the contract of the base class, but has a method with the same name. (For anyone who doesn't know the difference between new and override in C#, see this Microsoft Docs page).

  • You created an API, which has a class called Vehicle.

  • I started using your API and derived Vehicle.

  • Your Vehicle class did not have any method PerformEngineCheck().

  • In my Car class, I add a method PerformEngineCheck().

  • You released a new version of your API and added a PerformEngineCheck().

  • I cannot rename my method because my clients are dependent on my API, and it would break them.

  • So when I recompile against your new API, C# warns me of this issue, e.g.

    If the base PerformEngineCheck() was not virtual:

     app2.cs(15,17): warning CS0108: 'Car.PerformEngineCheck()' hides inherited member 'Vehicle.PerformEngineCheck()'.
     Use the new keyword if hiding was intended.
    

    And if the base PerformEngineCheck() was virtual:

     app2.cs(15,17): warning CS0114: 'Car.PerformEngineCheck()' hides inherited member 'Vehicle.PerformEngineCheck()'.
     To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
    
  • Now, I must explicitly make a decision whether my class is actually extending the base class' contract, or if it is a different contract but happens to be the same name.

  • By making it new, I do not break my clients if the functionality of the base method was different from the derived method. Any code that referenced Vehicle will not see Car.PerformEngineCheck() called, but code that had a reference to Car will continue to see the same functionality that I had offered in PerformEngineCheck().

EDIT: While going through the comments, I also came across a write-up by Eric Lippert (then one of the members of C# design committee) on other example scenarios (mentioned by Brian).

The claim was made that I was an "original member" of the design committee; I was not. I joined the committee as C# 3 specifications were being finalized, and left during the C# 6 process.
Source Link
Eric Lippert
  • 46.4k
  • 22
  • 91
  • 128

EDIT: While going through the comments, I also came across a write-up by Eric Lippert (onethen one of the original members of C# design committee) on other example scenarios (mentioned by Brian).

EDIT: While going through the comments, I also came across a write-up by Eric Lippert (one of the original members of C# design committee) on other example scenarios (mentioned by Brian).

EDIT: While going through the comments, I also came across a write-up by Eric Lippert (then one of the members of C# design committee) on other example scenarios (mentioned by Brian).

Clarified that the decision to override or not rests both on base & derived classes
Source Link
Omer Iqbal
  • 3.3k
  • 16
  • 22

A similar example is when another method in the base class might be calling PerformEngineCheck() (esp. in the newer version), how does one prevent it from calling the PerformEngineCheck() of the derived class? In Java, that decision would rest with the base class, but it does not know anything about the derived class. In C#, that decision would rest withrests both on the base class (via the virtual keyword), and on the derived class via(via the new and override keywords).

A similar example is when another method in the base class might be calling PerformEngineCheck() (esp. in the newer version), how does one prevent it from calling the PerformEngineCheck() of the derived class? In Java, that decision would rest with the base class, but it does not know anything about the derived class. In C#, that decision would rest with the derived class via the new and override keywords.

A similar example is when another method in the base class might be calling PerformEngineCheck() (esp. in the newer version), how does one prevent it from calling the PerformEngineCheck() of the derived class? In Java, that decision would rest with the base class, but it does not know anything about the derived class. In C#, that decision rests both on the base class (via the virtual keyword), and on the derived class (via the new and override keywords).

list formatting
Source Link
svick
  • 10.1k
  • 1
  • 39
  • 52
Loading
Added response, based on updated question
Source Link
Omer Iqbal
  • 3.3k
  • 16
  • 22
Loading
Sentence structure, clarity, additional example
Source Link
Omer Iqbal
  • 3.3k
  • 16
  • 22
Loading
Added a link to Eric Lippert's article
Source Link
Omer Iqbal
  • 3.3k
  • 16
  • 22
Loading
change link to msdn
Source Link
Omer Iqbal
  • 3.3k
  • 16
  • 22
Loading
added 411 characters in body
Source Link
Omer Iqbal
  • 3.3k
  • 16
  • 22
Loading
added 411 characters in body
Source Link
Omer Iqbal
  • 3.3k
  • 16
  • 22
Loading
Source Link
Omer Iqbal
  • 3.3k
  • 16
  • 22
Loading