none
Can I have a default constructor in a derived class? RRS feed

  • Question

  • I'm using Visual Studio 2017 Community.

    I have a class defined like this:

    namespace Nop.Plugin.Misc.LakesideImport.ExportImport { /// <summary> /// Import manager /// </summary> public class LakesideImportManager : ImportManager

              public LakesideImportManager()
              {
              }


    Can LakesideImportManager have a default constructor as indicated by what I have in the above code?

    I get an error on it that says:

    There is no argument given that corresponds to the required formal parameter 'productService' of 'ImportManager.ImportManager'(IProductService ... and 24 other interfaces)'

    Any help would be gratefully appreciated.

    Thanks,
    Tony


    Stop The World, I want To Get Off! ........... Life Isn't About Waiting For The Storm To Pass ... It's About Learning To Dance In The Rain.

    Saturday, September 30, 2017 2:31 PM

Answers

  • Yes. Constructors are never virtual and therefore each type must define the ctor(s) it wants exposed. You don't inherit them, However you still need to ensure that your type calls the base type ctor(s) that you want. So you often end up having to define ctor(s) just to make the base type happy.

    That is what is going on here. ImportManager doesn't have a default ctor. Therefore your ctor(s) must call one of the appropriate overloads for the base class. Because the base class has no default ctor, you must define at least 1 ctor yourself - default or otherwise. In general you tend to do one of the following.

    1. Expose the same ctors as the base type because the dependencies are the same.
    2. Expose simpler ctors that pass reasonable values for the derived type to the base type.
    //Assumed ctors for base class
    ImportManager ( IProductService productService, ISomeService someService, ... )
    {}
    
    public class LakesideImportManager : ImportManager
    {
       //Define a default ctor if you know all the values to use for the base ctor call
       public LakesideImportManager () : base(new ProductService(), new SomeService(), ...)
       { }
    
       //Expose additional ctors if you want to allow derived types/calling code to override some of the values being used
       public LakesideImportManager ( IProductService productService ) : base(productService, new SomeService())
       { }
    }

    If, in fact, your base type requires 24 parameters then I think it really needs to be refactored. If you go above a couple of parameters then a new type makes more sense. I would recommend that you create a new type (could be interface or a simple struct) that exposes all these objects. Then your ctor can simply use the aggregate type without the need for lots of overloads. If you're using DI then many of them allow throw-away interfaces that can be auto-populated for you so you don't even have to create an instance of the type, if you want to go that route.

    Michael Taylor
    http://www.michaeltaylorp3.net

    • Marked as answer by Carneno Monday, October 2, 2017 6:35 PM
    Saturday, September 30, 2017 3:06 PM
    Moderator

All replies

  • Yes. Constructors are never virtual and therefore each type must define the ctor(s) it wants exposed. You don't inherit them, However you still need to ensure that your type calls the base type ctor(s) that you want. So you often end up having to define ctor(s) just to make the base type happy.

    That is what is going on here. ImportManager doesn't have a default ctor. Therefore your ctor(s) must call one of the appropriate overloads for the base class. Because the base class has no default ctor, you must define at least 1 ctor yourself - default or otherwise. In general you tend to do one of the following.

    1. Expose the same ctors as the base type because the dependencies are the same.
    2. Expose simpler ctors that pass reasonable values for the derived type to the base type.
    //Assumed ctors for base class
    ImportManager ( IProductService productService, ISomeService someService, ... )
    {}
    
    public class LakesideImportManager : ImportManager
    {
       //Define a default ctor if you know all the values to use for the base ctor call
       public LakesideImportManager () : base(new ProductService(), new SomeService(), ...)
       { }
    
       //Expose additional ctors if you want to allow derived types/calling code to override some of the values being used
       public LakesideImportManager ( IProductService productService ) : base(productService, new SomeService())
       { }
    }

    If, in fact, your base type requires 24 parameters then I think it really needs to be refactored. If you go above a couple of parameters then a new type makes more sense. I would recommend that you create a new type (could be interface or a simple struct) that exposes all these objects. Then your ctor can simply use the aggregate type without the need for lots of overloads. If you're using DI then many of them allow throw-away interfaces that can be auto-populated for you so you don't even have to create an instance of the type, if you want to go that route.

    Michael Taylor
    http://www.michaeltaylorp3.net

    • Marked as answer by Carneno Monday, October 2, 2017 6:35 PM
    Saturday, September 30, 2017 3:06 PM
    Moderator
  • CoolDadTx,

    Thanks for your detailed and informative answer to my question.

    I actually already have a constructor in my derived class that is the same as the second example in your coding samples.  I just don't use the "new" in the ": base" parameter.  My project is working the way it is.

    When I try to put the empty constructor in my derived class, I get the error.  Am I supposed to be able to have a default constructor in my derived class in addition to the constructor as explained above?

    Thanks,
    Tony


    Stop The World, I want To Get Off! ........... Life Isn't About Waiting For The Storm To Pass ... It's About Learning To Dance In The Rain.


    • Edited by Carneno Monday, October 2, 2017 5:29 PM
    Monday, October 2, 2017 5:25 PM
  • Your derived type can have a default constructor. But you must have your default constructor call one of the valid base constructors. The error is telling you that the base type ImportManager does not have a default constructor. Therefore you must explicitly call one of the base constructors and pass the appropriate parameters. That is what the first constructor in my sample code is doing. The derived type has a default constructor, but it is calling one of the non-default constructors on the base type. Given the error your base type has no default constructors so every constructor you define in the derived type must explicitly call one of the base constructors.
    Monday, October 2, 2017 5:48 PM
    Moderator
  • Thanks for your help CoolDadTx.

    Tony


    Stop The World, I want To Get Off! ........... Life Isn't About Waiting For The Storm To Pass ... It's About Learning To Dance In The Rain.

    Monday, October 2, 2017 6:35 PM