Practical Usage of Virtual Functions in C#

Virtual functions

Virtual methods are the key to polymorphism. A method marked as virtual can be overriden in derived classes, to alter or specialize the behavior of the class.

Example:

class Base
{
public virtual void SayHello()
{
Console.WriteLine("Hello from Base");
}
}

class Derived : Base
{
public override void SayHello()
{
Console.WriteLine("Hello from Derived");
}
}

static void Main()
{
Base x = new Base();
x.SayHello(); // Prints "Hello from Base"
x = new Derived();
x.SayHello(); // Prints "Hello from Derived"
}

Note that you can redeclare (not override) a method that is not virtual, but in that case it won't participate in polymorphism:

class Base
{
public void SayHello() // Not virtual
{
Console.WriteLine("Hello from Base");
}
}

class Derived : Base
{
public new void SayHello() // Hides method from base class
{
Console.WriteLine("Hello from Derived");
}
}

static void Main()
{
Base x = new Base();
x.SayHello(); // Prints "Hello from Base"
x = new Derived();
x.SayHello(); // Still prints "Hello from Base" because x is declared as Base
Derived y = new Derived();
y.SayHello(); // Prints "Hello from Derived" because y is declared as Derived
}

C# - when to use public int virtual, and when to just use public int

In order to truly understand the virtual keyword you are going to want to read up on Polymorphism in general:

Polymorphism is often referred to as the third pillar of
object-oriented programming, after encapsulation and inheritance.
Polymorphism is a Greek word that means "many-shaped" and it has two
distinct aspects:

  1. At run time, objects of a derived class may be treated as objects of a
    base class in places such as method parameters and collections or
    arrays. When this occurs, the object's declared type is no longer
    identical to its run-time type.

  2. Base classes may define and implement virtual methods, and derived
    classes can override them, which means they provide their own
    definition and implementation. At run-time, when client code calls the
    method, the CLR looks up the run-time type of the object, and invokes
    that override of the virtual method. Thus in your source code you can
    call a method on a base class, and cause a derived class's version of
    the method to be executed.

Once you understand these concepts better you might be able to determine whether or not the method you are creating from the book needs to be virtual or not.

Why are private virtual methods illegal in C#?

I note that there are two questions here. In the future you might consider posting two questions instead of combining two questions in one. When you combine questions like this often what happens is only the first one gets answered.

The first question is "why are private virtual methods illegal in C#?"

Here are the arguments against the "private virtual methods" feature:

  1. private virtual is only useful when you have a nested derived class. This is a useful pattern, but far less common than the non-nested derived class situation.

  2. If you desire to restrict the ability to override the method in non-nested derived classes then you can do so by restricting the ability of non-nested classes to derive from the base class; make all the base class constructors private. Therefore private virtual is not necessary to prevent overriding; protected virtual is sufficient, because the only derived classes will be nested.

  3. If you desire to restrict the ability to call a method in a non-nested derived class then you can make the method internal virtual and then tell your coworkers to not use that method. It is irritating to have this not be enforced by the compiler, but the compiler does not enforce any other semantic constraint on how a method is supposed to be used either; getting the semantics right is your business, not the compiler's, and you have to enforce that with appropriate code reviews. Therefore private virtual is not necessary to prevent calling; internal virtual plus code reviews is sufficient.

  4. It is possible to implement this pattern already with existing parts:

    abstract class C
    {
    private int CF() { whatever; }
    private Func<int> f;
    public C() { f = CF; }
    private int F() { return f(); }
    private class D : C
    {
    private int DF() { whatever; }
    public D() { f = DF; }
    }

    Now I have a method F which is effectively virtual, but can only be "overridden" by derived nested classes.

Since in every case either protected, internal or protected internal does the trick, private virtual is unnecessary. It's almost never the right thing to do, since you have to be already committed to using the nested derived class pattern. So, the language makes it illegal.

The arguments for are:

There have been times in real code when I've want a virtual method to be a private implementation detail of a class that I want to be extended both by non-nested internal classes and nested internal classes. Having to enforce the invariant that the internal method not be called by my coworkers is vexing; I'd like that to be enforced by the compiler without me having to jump through crazy hoops like making a field of delegate type, etc.

Also, there's simply the matter of consistency and orthogonality. It seems weird that two things that ought to be independent -- accessibility and virtualness -- have an effect on each other unnecessarily.

The arguments against the feature are pretty strong. The arguments for are pretty weak. Therefore, no such feature. I'd personally like it very much, but I totally understand why the design team has never taken me up on it. It's not worth the cost, and I would hate to not ship a better feature because we spent budget on a feature that benefits almost no one.

The second question is "Why in C# are you not able to override a private virtual method in a derived non-nested class?"

There are several reasons.

  1. Because you can only override what you can see. A private method is a private implementation detail of a base class and must not be accessible.

  2. Because allowing that has serious security implications. Remember, in C++ you almost always compile code into an application all at once. You have the source code for everything; everything is essentially "internal" from the C++ perspective most of the time. In C#, that's not at all the case. Third party assemblies can easily get at public types from libraries and produce novel extensions to those classes which can then be used seamlessly in place of instances of the base class. Since virtual methods effectively change the behaviour of a class, any code which depends for security reasons on invariants of that class needs to be carefully designed so that they do not depend on invariants guaranteed by the base class. Restricting accessibility of virtual methods helps ensure that invariants of those methods are maintained.

  3. Because allowing that provides another form of the brittle base class problem. C# has been carefully designed to be less susceptible to the brittle base class problem than other OO languages. If an inaccessible virtual method could be overridden in a derived class then that private implementation detail of the base class becomes a breaking change if altered. Providers of base classes should be free to change their internal details without worrying overmuch that they've broken derived classes which depend on them; ideally only the public, documented interface to a type needs to be maintained when implementation details change.

Should I mark all methods virtual?

In C# you have to mark method as virtual to make it possible to override. Does it mean that in C# you should mark all methods virtual (except a few ones that you don't want to be overridden), since most likely you don't know in what way your class can be inherited?

No. If the language designers thought that virtual should have been the default then it would have been the default.

Overridablility is a feature, and like all features it has costs. The costs of an overrideable method are considerable: there are big design, implementation and testing costs, particularly if there is any "sensitivity" to the class; virtual methods are ways of introducing untested third-party code into a system and that has a security impact.

If you don't know how you intend your class to be inherited then don't publish your class because you haven't finished designing it yet. Your extensibility model is definitely something you should know ahead of time; it should deeply influence your design and testing strategy.

I advocate that all classes be sealed and all methods be non-virtual until you have a real-world customer-focussed reason to unseal or to make a method virtual.

Basically your question is "I am ignorant of how my customers intend to consume my class; should I therefore make it arbitrarily extensible?" No; you should become knowledgable! You wouldn't ask "I don't know how my customers are going to use my class, so should I make all my properties read-write? And should I make all my methods read-write properties of delegate type so that my users can replace any method with their own implementation?" No, don't do any of those things until you have evidence that a user actually needs that capability! Spend your valuable time designing, testing and implementing features that users actually want and need, and do so from a position of knowledge.

Is it good practice to throw exceptions in virtual functions?

If you require that a method be implemented by derived classes, why not make it abstract instead of virtual? This will force the derived class to implement the member. If they do not want to, or cannot return an ObjectInfo they can choose to return null themselves.

What is the difference between an abstract method and a virtual method?

An abstract function cannot have functionality. You're basically saying, any child class MUST give their own version of this method, however it's too general to even try to implement in the parent class.

A virtual function, is basically saying look, here's the functionality that may or may not be good enough for the child class. So if it is good enough, use this method, if not, then override me, and provide your own functionality.

What is the use case for C# allowing to use new on a virtual method?

Use case:

  • Today, you use a 3rd party library and derive class Banana from class Fruit.
  • You implement a method called Peel in Banana. There is no Peel in Fruit.
  • Tomorrow, the 3rd party releases a new version of the library, including a virtual Fruit.Peel method
  • You recompile your code tomorrow. Do you want to override Fruit.Peel? Quite possibly not - it could have a completely different meaning. Instead, you hide it with Banana.Peel and all the existing code works as it does today.

In other words, it's mostly to avoid versioning issues. In Java, you'd end up overriding Fruit.peel even though you didn't want to, quite possibly leading to hard-to-diagnose bugs.



Related Topics



Leave a reply



Submit