-1

I'm trying to call derived methods in a base constructor. I'd hoped the code below would result in a print of "Hello Derived" (specifically due to calling ParseData as a method of this.

using System;

public class Program
{
    public static void Main()
    {
        Derived a = new Derived("Hello");
    }

    public class Base
    {
        public Base(string s)
        {
            this.ParseData(s);
        }
        protected void ParseData(string s)
        {
            Console.WriteLine(s+ " Base");
        }
    }

    public class Derived : Base
    {
        public Derived(string s) : base(s){}
        new private void ParseData(string s)
        {
            Console.WriteLine(s + " Derived");
        }
    }
}

I understand from the answer to this previous question why it doesn't work as I'd hoped it would - but can anyone provide suggestions of how best to implement my desired effect without resorting to having to call ParseData in my calling code after construction is complete every time this object in constructed - as below - if at all possible. (I'm likely to have a lot of different derived classes to do this on...)

Thanks!

using System;

public class Program
{
    public static void Main()
    {
        string s = "Hello";
        Derived a = new Derived(s);
        a.ParseData(s);
    }

    public class Base
    {
        public Base(string s)
        {}
        protected void ParseData(string s)
        {
            Console.WriteLine(s+ " Base");
        }
    }

    public class Derived : Base
    {
        public Derived(string s) : base(s){}
        new private void ParseData(string s)
        {
            Console.WriteLine(s + " Derived");
        }
    }
}
JRVeale
  • 394
  • 2
  • 10
  • 2
    instead of using `new private void ParseData`- which is **hiding** the base-implementaion, you should make that method `virtual` within your base-class and `override` it in your derived one. – MakePeaceGreatAgain Feb 27 '20 at 14:08
  • 1
    You need the method to be `protected virtual` in `Base`, then `protected override` in `Derived`. However, calling a `virtual` member from constructor is not a good idea: https://stackoverflow.com/q/119506/1625737 – haim770 Feb 27 '20 at 14:09
  • 1
    By the way: **do not call virtual methods in constructors at all**! It is a design flaw and a dangerous implementation. Read more [in this question](https://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor). – dymanoid Feb 27 '20 at 14:20
  • You cannot safely do what you want, unfortunately - you will have to rethink this approach. – Matthew Watson Feb 27 '20 at 14:20

4 Answers4

2

As you have realised, you cannot safely call a virtual method from a base class' constructor.

C# allows you to do so, but the call to the derived class's overridden method will be executed in a context where the derived class's fields have not been initialised - which is likely to spell disaster.

There is an approach you can take to mitigate this problem. It's not perfect, since it puts the onus on derived classes to do things properly, but does at least mean that client code that is creating the objects doesn't need to do anything special.

It goes like this:

  1. Make the base class AND the method you want to call abstract in the base class declaration. This is to force derived classes to implement it. (You can give the method a body in the base class if there's some common code you want to call from derived classes.)
  2. Make the constructor of the base class protected. This is not strictly necessary if the base class is abstract, but it is conventional to do so.
  3. Each derived class must implement the abstract method from the base class.
  4. Make the constructor of every derived class private so that you can force client code to use a factory method to create it (see later step).
  5. Each derived class must implement a static factory method that can be used to create an instance of the class. This method should call the overridden method.

It sounds like a lot, but actually it boils down to the following for your example:

public abstract class Base
{
    protected Base(string s)
    {
        // Do something with s? Remove if not needed!
    }

    // Make this abstract so it must be overridden by a derived class.

    protected abstract void ParseData(string s);
}

public class Derived : Base
{
    public static Derived Create(string s)
    {
        var result = new Derived(s);
        result.ParseData(s);
        return result;
    }

    private Derived(string s) : base(s)  // Private to force use of Create().
    {
        // Whatever.
    }

    protected override void ParseData(string s)
    {
        Console.WriteLine(s + " Derived");
    }
}

Now when client code wants to create an instance of the derived class, it must use Derived.Create(s) to do so rather than new Derived(s) (which won't compile due to the constructor being private).

And when the client code does create an instance of the derived class, the derived ParseData() will always be called, e.g.:

static void Main()
{
    var a = Derived.Create("Hello");
}

Note: I've made ParseData() protected, like you did in your original code, but it doesn't have to be protected; it could be public if necessary.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
1

In your base class, you need to add the abstract or virtual modifier to the method you want to override in specific implementations.

abstract: You only declare the method signature in the base class and all derived class MUST implement it. Note: the class must also be abstract.

virtual: Similar to abstract, but with this, you can provide a method body that will act as a default implementation for derived classes. Basically, you'll have the choice to override it or not in your derived classes.

Here's an example using virtual

using System;

public class Program
{
    public static void Main()
    {
        string s = "Hello";
        Derived a = new Derived(s);
        a.ParseData(s);
    }

    public class Base
    {
        public Base(string s)
        {}
        protected virtual void ParseData(string s)
        {
            Console.WriteLine(s+ " Base");
        }
    }

    public class Derived : Base
    {
        public Derived(string s) : base(s){}
        protected override void ParseData(string s)
        {
            Console.WriteLine(s + " Derived");
        }
    }
}
  • 2
    Perhaps a brief explanation would add more value to your answer? For example, why `virtual` and `override` are useful in the OP's scenario? – Martin Feb 27 '20 at 14:10
  • This doesn't fulfil the OP's requirement: `how best to implement my desired effect without resorting to having to call ParseData in my calling code after construction is complete` – Matthew Watson Feb 27 '20 at 14:11
0

By using new you completely hide a member from your base-class. So actually you have two members that tend to have the exact same name. So when you have a reference of type Derived, the new member is used, otherwiese the base-class member is used.

In your case you have a new private member. This way you not only hide the base-class member, you also make it impossible to anyone outside Derived to access the new member, because it is private.

Best would be to make your base-class member virtual and the override it in your derived class:

public class Base
{
    public Base(string s)
    {}
    protected virtual void ParseData(string s)
    {
        Console.WriteLine(s+ " Base");
    }
}

public class Derived : Base
{
    public Derived(string s) : base(s){}
    protected override void ParseData(string s)
    {
        Console.WriteLine(s + " Derived");
    }
}

If you can´t change your base-class, you have to use new. However you have to use an access-modifier which allows access from the outside, e.g. internal:

public class Derived : Base
{
    public Derived(string s) : base(s){}
    internal new void ParseData(string s)
    {
        Console.WriteLine(s + " Derived");
    }
}

This assumes Derived is in the same assembly as your Main.

Apart from this you may get issues when calling virtual members in your constructor. It may work, if you do not use any members that are not yet initialized because of the order in which the constructor are executed - from most basic to most derived. However I´d stronly discourage you from doing so. See this question for details: Virtual member call in a constructor

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
0

You can't do this safely in C#. Constructors are executed in order from the least specific to most specific - in your case, Base followed by Derived. To call a method on Derived from Base, you would need to make a virtual (or abstract) method on Base. But calling that in the Base constructor is a bad idea - the Derived constructor didn't execute yet! The override method might rely on stuff that isn't initialized.

If you can, instead of using a constructor, expose a public static method for each type. This allows you to safely initialize the object, call your virtual method, and return the finished type.

Luaan
  • 62,244
  • 7
  • 97
  • 116