Search code examples
c#inheritanceconstructordefault-constructorenforcement

Can't enforce the use of base constructor of an abstract class into derived class


I am trying to enforce the use of a specific parameterised constructor in my derived classes as per this below answer:

Abstract Class with Constructor

Using the example provided in the above answer, the code compilation fails as expected. Even after modifying the code in order to make it resemble mine it still fails. My actual code though compiles just fine. I am at a loss here why that is.

Here is the modified example from the provided answer (which wont compile as expected):

public interface IInterface
{
    void doSomething();
}


public interface IIInterface : IInterface
{
    void doSomethingMore();
}


public abstract class BaseClass : IIInterface
{
    public BaseClass(string value)
    {
        doSomethingMore();
    }

    public void doSomethingMore()
    {

    }

    public void doSomething()
    {

    }
}


public sealed class DerivedClass : BaseClass
{
    public DerivedClass(int value)
    {

    }

    public DerivedClass(int value, string value2)
        : this(value)
    {

    }
}

Now my code that compiles without a hitch:

public interface IMethod
{
    Url GetMethod { get; }
    void SetMethod(Url method);
}


public interface IParameterizedMethod : IMethod
{
    ReadOnlyCollection<Parameter> Parameters { get; }
    void SetParameters(params Parameter[] parameters);
}


public abstract class ParameterizedMethod : IParameterizedMethod
{

    public ParameterizedMethod(params Parameter[] parameters)
    {
        SetParameters(parameters);
    }


    private Url _method;
    public Url GetMethod
    {
        get
        {
            return _method;
        }
    }

    public void SetMethod(Url method)
    {
        return _method;
    }


    public ReadOnlyCollection<Parameter> Parameters
    {
        get
        {
            return new ReadOnlyCollection<Parameter>(_parameters);
        }
    }

    private IList<Parameter> _parameters;

    public void SetParameters(params Parameter[] parameters)
    {

    }
}


public sealed class AddPackageMethod : ParameterizedMethod
{
    public AddPackageMethod(IList<Url> links)
    {

    }

    public AddPackageMethod(IList<Url> links, string relativeDestinationPath)
        : this(links)
    {

    }

    private void addDownloadPathParameter(string relativeDestinationPath)
    {

    }

    private string generatePackageName(string destination)
    {
        return null;
    }

    private string trimDestination(string destination)
    {
        return null;
    }

}

I removed the implementation in some of the methods to keep it as concise as possible. As a side note my actual code might be lacking in areas. Consider those parts WIP.

Update 1/Solution:

As per sstan's answer below pointing out the implications of using the keyword 'params' here is the corrected passage of my code which makes it behave as intended (fails on compilation):

public abstract class ParameterizedMethod : IParameterizedMethod
{
    public ParameterizedMethod(Parameter[] parameters) // **'params' removed**
    {
        SetParameters(parameters);
    }
     // original implementation above      
}

Solution

  • The following constructor attempts to invoke the base class' constructor without any parameters.

    public AddPackageMethod(IList<Url> links)
    {
    
    }
    

    Well, it just so happens that your base class' constructor can be invoked without any parameters because of the params keyword. So it compiles fine.

    public ParameterizedMethod(params Parameter[] parameters)
    {
        SetParameters(parameters);
    }
    

    Just for testing, if you remove the params keyword, thus forcing a parameter to be passed, your code will not compile, just as you were expecting.