views:

143

answers:

2

Hi, I am facing this strange problem while working with Generic Base Classes. I am having three levels of base class hierarchy while the fourth level is the concrete class. Something as below.

// Level 0 (Root Base Class)    
public abstract class BusinessDataControllerBase<BDA> : IBusinessDataController
{
    protected BDA da;
    public BusinessDataControllerBase()
    {
    // Initialize the respective Data Access Layer passed by the concrete class
    BDA da = new BDA();
    }
}


// Level 1 (Second Level Base Class)
public abstract class BusinessRootDataControllerBase<BDA> : BusinessDataControllerBase<BDA>, IBusinessRootDataController
        where BDA : IBusinessDALController, new()
{
}

// Level 2 (Third Level Base Class)
public abstract class BusinessMasterRootDataControllerBase<BRC, BRD, BDA> : BusinessRootDataControllerBase<BDA>, IDisposable
        where BRC : IBusinessRootDataController 
        where BRD : IBusinessRootData
        where BDA : IBusinessDALController, new()
{
}

// Level 3 (Concrete Class)
public class UserController : BusinessMasterRootDataControllerBase<UserController, UserData, UsersDAL>
{
        # region Singleton implementation - Private Constructor, Static initialization
        private static readonly UserController instance = new UserController();
        public static UserController Instance
        {
            get { return instance; }
        }
        # endregion

        # region Constructor
        // --------------------------------------------------------------------------------
        //Private Constuctor
        private UserController()
        {
        }
        // --------------------------------------------------------------------------------

       private void DoLogin(string userName, string password)
        {
            DataSet dstUser = da.GetUser(userName);
            // Check user name
            // Check password
        }
}

What I want to achieve is absolute simple. I need the 'da' object to be instantiated at the top level base class. The concrete type 'UsersDAL' is supplied by the concrete class UserController and the correct type should be propagated till the top level base class (BusinessDataController) where it should be instantiated.

Now while I am debugging the BusinessDataController, I can see that the type (UsersDAL) is being propagated, a new UsersDAL() object is getting created in BusinessDataControllerBase() constructor but as soon as the code is coming out of the constructor in BusinessDataControllerBase, the 'da' member variables shows as 'null' and hence the DoLogin() process da.GetUser() is giving an error (object not instantiated).

But, if instead of instantiating 'da' in BusinessDataController, I create it in BusinessMasterRootData controller (at Level 2, i.e. the class just above the concrete class UserController), then everything is running fine and da.GetUser() works as expected.

I have tried to explore inheritance impacts of Generics (closed construction and open construction etc.) but could not find any deviations in my code. In design/compile time, I am not getting any error and getting all methods of UsersDAL with IntelliSense which possibly indicates that the type usage is correct.

Any idea where am I going wrong? I will have multiple base classes at the third level, i.e. the 'BusinessMasterRootDataControllerBase' level. So instantiating 'da' at the third level will make 'da' available in the concrete classes but will be redundant in all classes at that level and that is why I want to place it ('da') higher up. By the way, same observation is happening if I place the constructor code at the second level (i.e. BusinessRootDataControllerBase).

Another information to share is I am using the UserController (concrete class) as a Singleton class.

Any help is appreciated.

+2  A: 

in

protected BDA da;
public BusinessDataControllerBase()
{
  // Initialize the respective Data Access Layer passed by the concrete class
  BDA da = new BDA();
}

There are two items named 'da', you are assigning a new BDA() to a local variable that goes out of scope immediately. It probably should look like:

protected BDA da;
public BusinessDataControllerBase()
{
  // Initialize the respective Data Access Layer passed by the concrete class
  da = new BDA();
}
Henk Holterman
Thanks buddy. It was silly to have missed that out. It took me 4 hours of stupid research with no results. Excellent observation.
Rajarshi
A: 

Maybe I'm just missing the point, but you should explicitly call the base class constructors in your hierarchy.

This should work:

// Level 0 (Root Base Class)     
public abstract class BusinessDataControllerBase<BDA> : IBusinessDataController 
{
   protected BDA da;

   public BusinessDataControllerBase()
   {
      // Initialize the respective Data Access Layer passed by the concrete class
      this.da = new BDA();
   } 
}        

// Level 1 (Second Level Base Class) public abstract class 
BusinessRootDataControllerBase<BDA> : BusinessDataControllerBase<BDA>, IBusinessRootDataController
                    where BDA : IBusinessDALController, new() 
{ 
   public BusinessRootDataControllerBase()
      : base() {}     
}

// Level 2 (Third Level Base Class) public abstract class BusinessMasterRootDataControllerBase<BRC, BRD, BDA> : BusinessRootDataControllerBase<BDA>, IDisposable
      where BRC : IBusinessRootDataController 
      where BRD : IBusinessRootData
      where BDA : IBusinessDALController, new() 
{ 
   public BusinessMasterRootDataControllerBase()
      : base() {} 
}

// Level 3 (Concrete Class) public class UserController : BusinessMasterRootDataControllerBase<UserController, UserData, UsersDAL> 
{
   # region Singleton implementation - Private Constructor, Static initialization
   private static readonly UserController instance = new UserController();

   public static UserController Instance
   {
      get { return instance; }
   }
   # endregion

   # region Constructor
   // --------------------------------------------------------------------------------
   //Private Constuctor
   private UserController()
      : base()
   {
   }
   // --------------------------------------------------------------------------------

   private void DoLogin(string userName, string password)
   {
      DataSet dstUser = da.GetUser(userName);
      // Check user name
      // Check password
   } 
}
m0rb
As long as there are no parameters, you don't have to call them explicitly. The compiler will insert :base()
Henk Holterman