Thursday, March 26, 2009

Inheritance: returning to the basics of OOP

According to MSDN:

Inheritance, together with encapsulation and polymorphism, is one of the three primary characteristics (or pillars) of object-oriented programming.

It is very simple to do it in C#, but sometimes we can fall in some traps.
Today we had a very interesting problem. How to prevent a child class to override a base class method?
Lets go to our problem: We have a base class called ContentPageBase that inherits from System.Web.UI.Page. And we want to use it as base for our WebContentPages.
But, we want to prevent those child pages to access the method Page_Load(). How to do it?
Simple, there is a class type named "abstract". Lets go again consult the MSDN:

The abstract keyword enables you to create classes and class members that are incomplete and must be implemented in a derived class.(..)An abstract class cannot be instantiated. The purpose of an abstract class is to provide a common definition of a base class that multiple derived classes can share.

So we can define a common definition of the Page_Load() method that cannot be overloaded by the child classes. By defining a class as abstract, it blocks all the methods from being overrided unless you defined the method as virtual.

So the code will be like this:
public abstract class ContentPageTemplate : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Page.Title = "Calling from Base Class";
}
}
If you try to override the method by implementing the child class:

public partial class WebContent1 : ContentPageTemplate
{
protected override void Page_Load(object sender, EventArgs e)
{
Page.Title = "Hello ";
}
}

When compiling the following error will appear:
cannot override inherited member 'ContentPageTemplate.Page_Load(object, System.EventArgs)' because it is not marked virtual, abstract, or override

Actually there is no way to prevent the child class to just write a new method with the same name, but you can avoid the overriding by creating abstract classes.
If you don't define a class as abstract, the compiler will automatically convert all the methods as virtual, and you lose the control over them.

6 comments:

Teguh Eko Budiarto said...

Why do you want to prevent the child class to override a base class method, specially if the method is the page load?

Maybe you want to make sure that the inherited class always execute the base class method? In this case, I think we should not prevent the inherited class to override the base method. But, the inheritance class method should be suggested to always execute the base class method first.

Unknown said...

The problem we faced was that, if you DON'T place the base class as abstract, what happens is that you can replace the father method with your own without overloading the method... and this was our headache.

So, if you do something like:

public class ContentPageTemplate : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Page.Title = "Calling from Base Class";
}
}

And create your inherited class as:

public class WebContent1 : ContentPageTemplate
{
protected override void Page_Load(object sender, EventArgs e)
{
Page.Title = "Hello ";
}
}

And if you compile it, it will work, with a warning coming from the VS:

"Warning: hiding inherited method Page_Load()..."

And if you run the page, the result will be: "Hello".

That means, if we don't place as abstract, we could leave an open space to anyone to just re-define the main Page_Load method and ignore what we have set in the base class.

Teguh Eko Budiarto said...
This comment has been removed by the author.
Teguh Eko Budiarto said...

I think Page_Load method usually being customized for each page. So, if you really want to make page_load can not be overridden, then I suggest to make another method (e.g. after_page_load or even before_page_load) which is virtual, and call it inside the base page_load. That way, you can leave room for customization after/before your default procedure.

Anyway, IMO because the use of the base class is also a suggestion, then the default page_load should also be a suggestion. The user (in this case is the programmer) should understand what this class purpose and what is it capable of.

Remember that we can always override the event handler of the Page.Load by modifying method OnInit or the InitializeComponent.

Unknown said...

That's the idea... To add a method "Load()" inside the Page_Load() in the base class, and leave the "Load()" to be overridable, if needed.

But well noted, other methods also available in the Page class can override the Page_Load behavior in the base.

Fabiano Ozahata said...

The method Load already exist to System.Web.UI.Control.Load, Maybe use another type or change to "Load_Page" or "Start_Page"