1

I'm working on a software communicating with external device. The device requires a set of initialization values (calibrationData). Those calibration data differ from piece to piece of this equipment. In first versions the calibrationData can be selected by user and thus the user may by accident load calibrationData obtained on different piece. The device would work, but will measure incorrectly. I have

    public Instrument(CalibrationData calibration)
    {
        _camera = new Camera();
        _driver = new Driver();

        if (_camera.GetUniqueId() != calibration.GetCameraUniqueId())
           throw new WrongCalibrationException("Calibration file was obtained on different equipment.");
         //Don't write anything here. Exception has to be the last code in the constructor.
    }

and then somewhere else

try
{
    instrument = new Instrument(calibration);
}
catch (WrongCalibrationException e)
{
    MessageBox.Show("You tried to load calibration obtained on different device.");
}

I'm not able to check the ID before I'm connected to the device.

This question comprises out of two in fact.

  1. Is my solution correct? I want to test usage of proper calibration automatically and not rely on the programmer using use my code to call another method (Something like Instrument.AreYouProperlyCalibrated())

  2. Is the object constructed properly when the exception is thrown at the end of constructor? I'm a bit afraid that C# is doing some mumbo jumbo after the construcor finishes and that this might be different in case the ctor threw an exception.

Thanks

Ehsan Zargar Ershadi
  • 24,115
  • 17
  • 65
  • 95
Biggles
  • 1,306
  • 1
  • 12
  • 22
  • Marc and Yuriy cover pretty much everything I think. I'll just add that any finaliser you have for the class will still be run even though the constructor isn't fully completed so be aware of that in a finalizer (which you dont appear to have anyway). – Russell Troywest Dec 16 '11 at 08:24

5 Answers5

3

The instance already fully exists before the constructor begins (indeed, you can even completely bypass all constructors and still get a valid instance) - it just means that any initialization code that didn't execute won't have executed.

For example, while it isn't a good idea, you can pass the object instance out of the type during the constructor, i.e.

_camera.HereIsMe(this);

or

SomeExternalObject.Track(this);

so nothing too terrible will happen, since as far as the runtime is concerned this object exists like normal, and must be handled properly. However, in some cases it is cleaner to use a factory:

public static YourType Create(args) {
    // TODO: perform enough work to validate
    return new YourType(validated args);
}

But to reiterate; if there is a problem, then throwing from the constructor is not unexpected and is not harmful.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Passing an instance out of a `protected` constructor (making it available to a factory method) can be a very good idea, if the object in question implements IDisposable. A factory method which wraps the constructor can then call Dispose on the partially-constructed object. The Dispose routine will have to be written to handle this possibility, of course, but for derived classes, the pattern seems cleaner than putting 'try' blocks in every constructor. – supercat Dec 16 '11 at 17:42
2

It's a matter of preference. For example, DateTime throws an exception in its constructor. If you'd rather not, you could use a static method like Build(Calibration calibration). A good practice is to use XML comments to let users of your type know that the constructor throws an exception in an <exception> tag.

Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
2

You can throw exceptions from wherever you want in your code.

If your constructor has a throw somewhere, and that throw occurs, the object won't be created or, to be more correct, it will be created but your code execution flow will follow the exception, so you won't be in the code branch where the object was being created, so it's like it was not created at all for what concerns you.

So I'd say your approach, considering only the code you posted, is ok. Obviously there could be other problems related to things that could be in the Camera and Driver constructors (stuff not disposed, etc) but that's another matter.

Matteo Mosca
  • 7,380
  • 4
  • 44
  • 80
1

it's a contentious subject, but at the end of the day it is perfectly valid to throw exceptions in constructors. here are some links that discuss and validate the practice:

Throwing ArgumentNullException in constructor?

http://bytes.com/topic/c-sharp/answers/518251-throwing-exception-constructor

http://blog.aggregatedintelligence.com/2009/04/can-constructors-throw-exceptions.html

Community
  • 1
  • 1
Jason
  • 15,915
  • 3
  • 48
  • 72
0

I would like to add to Marc's answer by pointing out that the Camera and Driver objects should be getting injected into the class. See this (one of MANY) article(s) on implementing Dependency Injection in C#

Hopefully I won't get flogged for this being an opinion. ;)

Scott Fraley
  • 378
  • 4
  • 14