views:

1486

answers:

3

My problem here is that I would like to pass an object to a derived class, but it must be done before the base class constructor, since the base class will immediately call the derived class's Start() method that uses the object.

Here's an excerpt from the base class, (renamed from BarcodeScanner for convenience).

public abstract class MyBase
{    
    public MyBase()
    {
        if (Initialize())
            this.Start();
    }

    public abstract bool Initialize();
    public abstract void Start();
}

Here's the derived class that I'm creating.

class MyDerived : MyBase
{
    private string sampleObject;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
    }

    public override bool Initialize() 
    { 
        return GetDevice();
    }
    public override void Start() 
    { 
        Console.WriteLine("Processing " + sampleObject.ToString()); 
    }
}

I doubt you can make C# execute a derived constructor before the base constructor; so I'm really just looking for a solution to pass an object to the derived class before the object is used.

I've gotten around this by putting the Initialize/Start if block inside the MyDerived constructor. However, there are other classes deriving from the base class; so I ended up having to repeat this block of Initialize/Start code in every derived class. I'd like to see an alternative to modifying the base class.

+3  A: 

What you are trying to do is impossible in C#. A constructor in a base class must be run before the constructor of any derived class otherwise there would be potential for corrupt object state. A child object must be able to assume that its base is fully constructed and available.

Andrew Hare
Well, it is possible to create empty override Initialize/Start methods, and move those code into derivedInitialize/derivedStart methods, and then in the derived constructor, call `if (derivedInitialize()) derivedStart()`. There may be no elegant solutions, but there are still other ways.
James
+12  A: 

IMHO your design is wrong. You shouldn't start the process from within the constructor. Your consuming code should explicitly call the Start() method when required.

AdamRalph
+1 For explict calling of "Start()".
Andrew Hare
+1. This guy is correct, you need .Start() / .Initialise(). Don't call virtual methods in constructors.
Quibblesome
+1. C++ restricts virtual calls from constructors for a reason.
Anton Tykhyy
I wholeheartedly agree that the design from MSDN isn't perfect, but it's been already implemented and it works well with the derived classes that don't need a passed in object.
James
MSDN is advocating such a design? Can you post a link please?
AdamRalph
+1. This is why famous "InitializeComponent" appeared. You should spit construction and initialization logic. Make your "Initialize" let's say "protected virtual" and override it in the derived classes. You'll be able to decide whether "base.InitializeComponent" call should go first or last.
Denis Vuyka
The link to the MSDN page is in the question. BarcodeScanner is the abstract class on the page titled "Bar Code Scanners with the .NET Compact Framework". It's an old page, but still useful.
James
A: 

I would rework your design so that Initialize (and potentially Start() - though I'd normally have this be a public method that's called by the user) are called after construction.

If you're making a BarcodeScanner, you could do this the first time you go to scan. Just lazy-initialize your members using the data from the derived class.

This will work around your issue, with no real change in usage from the user.

Reed Copsey
The scan is initiated asynchronously by the device, so you can't initialize based on scan start. In hindsight, Microsoft should've renamed their Start() method to be Ready() method. Since the Start() method only readies the scanner, but doesn't actually start the scan.
James