我正在开发与外部设备通信的软件。该设备需要一组初始化值(calibrationData)。这些校准数据因设备而异。在第一版本中,校准数据可以由用户选择,因此用户可能意外地加载在不同件上获得的校准数据。该设备可以工作,但测量不正确。 我有
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.
}
然后在其他地方
try
{
instrument = new Instrument(calibration);
}
catch (WrongCalibrationException e)
{
MessageBox.Show("You tried to load calibration obtained on different device.");
}
在连接到设备之前,我无法检查ID。
这个问题实际上包含两个。
我的解决方案是否正确?我想自动测试正确校准的使用,而不是依赖程序员使用我的代码调用另一种方法(像Instrument.AreYouProperlyCalibrated())
在构造函数结束时抛出异常时,是否正确构造了对象?我有点害怕在构造完成后C#正在做一些mumbo jumbo,并且如果ctor抛出异常,这可能会有所不同。
由于
答案 0 :(得分:3)
在构造函数开始之前,实例已经完全存在(实际上,你甚至可以完全绕过所有构造函数并仍然获得一个有效的实例) - 它只是意味着任何未执行的初始化代码都赢了没有执行。
例如,虽然不是一个好主意,但您可以在构造函数中传递该类型的对象实例 out ,即
_camera.HereIsMe(this);
或
SomeExternalObject.Track(this);
所以没有太多可怕的事情会发生,因为就运行时而言,这个对象就像普通一样存在,必须妥善处理。但是,在某些情况下使用工厂更清晰:
public static YourType Create(args) {
// TODO: perform enough work to validate
return new YourType(validated args);
}
但重申一下;如果存在问题,那么从构造函数中抛出并不是意料之外的,并且没有害处。
答案 1 :(得分:2)
这是一个偏好问题。例如,DateTime
在其constructor中引发异常。如果您不愿意,可以使用Build(Calibration calibration)
之类的静态方法。一个好的做法是使用XML注释让您的类型的用户知道构造函数在<exception>
标记中抛出异常。
答案 2 :(得分:2)
您可以在代码中的任何位置抛出异常。
如果你的构造函数在某处抛出,并且抛出该对象,则不会创建该对象,或者更正确的是,它将被创建,但是你的代码执行流程将遵循异常,所以你不会在创建对象的代码分支中,所以就像根本没有创建对象一样。
所以我说你的方法,只考虑你发布的代码,没问题。显然,可能存在与Camera
和Driver
构造函数(未处理的东西等)相关的其他问题,但这是另一回事。
答案 3 :(得分:1)
这是一个有争议的主题,但在一天结束时,在构造函数中抛出异常是完全有效的。以下是一些讨论和验证实践的链接:
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
答案 4 :(得分:0)
我想通过指出相机和驱动程序对象应该被注入到课程中来添加Marc的答案。在implementing Dependency Injection in C#
上看到这个(许多之一)文章希望我不会因为这个意见而受到鞭挞。 ;)