Saturday, June 29, 2013

Inheritance and Constructors

I see frequent questions on the Forums where code doesn’t seem to work right and it comes down to the poster’s lack of understanding about the order in which the constructors are executed for the base class and a sub-class.

Here's a common scenario: say you have a base class that does some work (in the example I'll show, it is a generic class to fill a DataSet from SQL, based on the TableName property of the class). Each sub-class of this base class will provide it's own TableName property, because each sub-class will be filling it's own table.

The first attempt at creating these two classes, looks like this:

public class BizObj
{
    protected string TableName = "";
    private DataSet oData;

    public BizObj()
    {
        LoadData();
    }

    public void LoadData()
    {
        SqlConnection oConn = new SqlConnection("...");
        SqlDataAdapter oAdapter = new SqlDataAdapter("SELECT * FROM " + this.TableName, oConn);
        oAdapter.Fill(oData);

    }
}

public class AuthorBizObj : BizObj
{
    public AuthorBizObj()
    {
        this.TableName = "Authors";
    }
}

However, this does not work. Why? Because the BizObj (base class) constructor fires before the AuthorBizObj (sub-class) constructor, not the other way around. And then it's too late to set the TableName at that point.

The trick to fixing this is to use a virtual Property, rather than a member, and to override that Property in each sub-class:

public class BizObj
{
   public string m_TableName="";

   protected virtual string TableName
   {
      get {return this.m_TableName;}
      set {this.m_TableName = value;}
   }

   private DataSet oData;

   public BizObj()
   {
      LoadData();
   }

   public void LoadData()
   {
      SqlConnection oConn = new SqlConnection("...");
      SqlDataAdapter oAdapter = new SqlDataAdapter("SELECT * FROM "+this.TableName,oConn);
      oAdapter.Fill(oData);

   }
}

public class AuthorBizObj : BizObj
{
    protected override string TableName
    {
        get { return "Authors"; }
    }
}