Why C# implements methods as non-virtual by default?
Classes should be designed for inheritance to be able to take advantage of it. Having methods virtual
by default means that every function in the class can be plugged out and replaced by another, which is not really a good thing. Many people even believe that classes should have been sealed
by default.
virtual
methods can also have a slight performance implication. This is not likely to be the primary reason, however.
Why are C# interface methods not declared abstract or virtual?
For the interface, the addition of the abstract
, or even the public
keywords would be redundant, so you omit them:
interface MyInterface {
void Method();
}
In the CIL, the method is marked virtual
and abstract
.
(Note that Java allows interface members to be declared public abstract
).
For the implementing class, there are some options:
Non-overridable: In C# the class doesn't declare the method as virtual
. That means that it cannot be overridden in a derived class (only hidden). In the CIL the method is still virtual (but sealed) because it must support polymorphism regarding the interface type.
class MyClass : MyInterface {
public void Method() {}
}
Overridable: Both in C# and in the CIL the method is virtual
. It participates in polymorphic dispatch and it can be overridden.
class MyClass : MyInterface {
public virtual void Method() {}
}
Explicit: This is a way for a class to implement an interface but not provide the interface methods in the public interface of the class itself. In the CIL the method will be private
(!) but it will still be callable from outside the class from a reference to the corresponding interface type. Explicit implementations are also non-overridable. This is possible because there's a CIL directive (.override
) that will link the private method to the corresponding interface method that it's implementing.
[C#]
class MyClass : MyInterface {
void MyInterface.Method() {}
}
[CIL]
.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}
In VB.NET, you can even alias the interface method name in the implementing class.
[VB.NET]
Public Class MyClass
Implements MyInterface
Public Sub AliasedMethod() Implements MyInterface.Method
End Sub
End Class
[CIL]
.method public newslot virtual final instance void AliasedMethod() cil managed
{
.override MyInterface::Method
}
Now, consider this weird case:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
If Base
and Derived
are declared in the same assembly, the compiler will make Base::Method
virtual and sealed (in the CIL), even though Base
doesn't implement the interface.
If Base
and Derived
are in different assemblies, when compiling the Derived
assembly, the compiler won't change the other assembly, so it will introduce a member in Derived
that will be an explicit implementation for MyInterface::Method
that will just delegate the call to Base::Method
.
So you see, every interface method implementation must support polymorphic behavior, and thus must be marked virtual on the CIL, even if the compiler must go through hoops to do it.
Why methods in C# are not automatically virtual?
You should care which members can be overridden in derived classes.
Deciding which methods to make virtual should be a deliberate, well-thought-out decision - not something that happens automatically - the same as any other decisions regarding the public surface of your API.
Are methods virtual by default or not virtual?:
well, you got it right. If it's not virtual, it gets hidden.
The new
keyword brakes the virtual overriding in the inheritance hierarchy chain.
Simple example to read: Polymorphism, Method Hiding and Overriding in C#
Why are C# classes unsealed by default, when their methods are non-virtual by default?
I believe the question is "given that there are good reasons why methods should be non-virtual by default, why are classes not also sealed by default?"
One could also add: C# makes the default accessibility either internal, for top-level types, or private, for members of types; that is, it chooses the more restrictive and safer option; if a developer wishes a less restrictive, more dangerous option they can opt into it. Sealing by default would also be choosing the more restrictive and safer option as the default.
Also: unsealing a class is never a breaking change, but deciding later that you wish you'd made a class sealed and sealing it is a breaking change. C# typically prefers the design choice that encourages fewer breaking changes, so for this reason also, you would think that C# classes should be sealed by default.
We've identified three reasons why sealed by default is both a good idea and consistent with other design choices in C#. Why then is C# inconsistent in this regard, choosing to make unsealed classes the default?
I don't know. It's always struck me as a minor design flaw in C#. I've never seen a cogent argument for this choice, and I do not know if it was debated in early design meetings or not; that was before my time on the design team.
Unless you run into someone who was in that design meeting in 2001 and ask them, you might not get a satisfactory answer to your question.
I am in the habit of sealing every class I write unless I have a reason to design it for inheritance; I encourage everyone to do the same.
Why not make everything 'virtual'?
Eric Lippert covers this here, on method hiding
C# call an interface method non-virtual implementation
Because AAble
is implementing the IAble
interface, its AAble.f
is marked as the implementation of the IAble.f
method for type AAble
.
BAble.f
is simply hiding the AAble.f
method, it is not overriding it.
IAble o = new BAble(); o.f(); // calls AAble.f
AAble o = new BAble(); o.f(); // calls AAble.f
BAble o = new BAble(); o.f(); // calls BAble.f
IAble o = new CAble(); o.f(); // calls CAble.f
The decision is made at compile-time:
// AAble.f in IL:
.method public final hidebysig newslot virtual
instance void f () cil managed
// BAble.f in IL:
.method public hidebysig
instance void f () cil managed
Interface implementations are marked as virtual
in IL, even though it wasn't marked virtual in C#. The method is also marked as final
in IL, if the method would've been virtual
in C#, it would not have been marked as final
.
Why doesn't C# have a non-virtual calling convention?
This might explain it: http://blogs.msdn.com/b/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx
Shortly: call
instruction can accept null
as this
pointer (as it is in C++). This is errorsome and C# team decided to use callvirt
wherever it is possible so that calls on null
pointers throw NullReferenceException
Related Topics
Try/Catch + Using, Right Syntax
How to Implement Generic Repository Design Pattern with Dapper
How to Style Chat Window Using CSS When Using Microsoft Bot Framework
Copy Files from Resources/Streamingassets to Application.Persistentdatapath Upon Installation
How to Return JSON with ASP.NET & Jquery
How to Lock a Table on Read, Using Entity Framework
Using Image Control in Wpf to Display System.Drawing.Bitmap
Icollection<T> VS List<T> in Entity Framework
Unique File Identifier in Windows
How to Detect If a Property Exists on an Expandoobject
Environment.Tickcount VS Datetime.Now
How to Add CSS Class to HTML Generic Control Div
Xamarin iOS Memory Leaks Everywhere
Web Browser Control: How to Capture Document Events
How to Upload a File to an Sftp Server in C# (.Net)