实现 IDisposable 时处理构造函数中的异常
我读到,如果我的类有一个本身就是 IDisposable 的成员变量,我需要实现 IDisposable。好吧,我正在实现 IDisposable 接口,因为我的类包含一个数据库对象(下面的 db 类成员),它本身就是 IDisposable:
public class CommissionModel : IDisposable
{
protected PetaPoco.Database db;
public CommissionModel()
{
string connectionString = "Server=localhost;...";
// The line below may throw an exception (!!!)
db = new PetaPoco.Database(connectionString, "mysql");
}
// Automatically close database connection
public void Dispose()
{
if (db != null)
db.Dispose();
db = null;
}
public void InsertRecord(Record somerecord)
{
// ...
db.Insert(somerecord);
}
问题是 db 的实例化code> 成员在某些情况下可能会失败。 当构造函数抛出异常并且数据库对象没有创建时该怎么办?我应该重新抛出异常还是检查 InsertRecord 方法中是否 db != null
?
I read I need to implement IDisposable
if my class has a member variable that is itself IDisposable. Well, I am implementing IDisposable
interface because my class contains a database object (db
class member below) which is IDisposable itself:
public class CommissionModel : IDisposable
{
protected PetaPoco.Database db;
public CommissionModel()
{
string connectionString = "Server=localhost;...";
// The line below may throw an exception (!!!)
db = new PetaPoco.Database(connectionString, "mysql");
}
// Automatically close database connection
public void Dispose()
{
if (db != null)
db.Dispose();
db = null;
}
public void InsertRecord(Record somerecord)
{
// ...
db.Insert(somerecord);
}
The problem is instantiation of db
member may fail under some circumstances.
What should I do when the exception is thrown in the constructor and the database object gets not created? Should I rethrow the exception or maybe check if db != null
in InsertRecord method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果构造函数抛出异常,代码的使用者将永远不会收到对类实例的引用。部分初始化的类内存最终会被回收,并且不会调用Dispose。
我通常建议将由于外部情况(而不是由于误用,例如无效的参数值)而可能失败的操作移至单独的方法,例如“Connect”。
If your constructor throws an exception, the consumer of your code will never receive a reference to an instance of your class. The partially initialized class memory will eventually be collected and Dispose will not be called.
I would generally recommend moving an operation that can fail due to outside circumstances (and not due to misusage, like an invalid parameter value) to a separate method, like "Connect".
理想情况下,您不应在构造函数中执行任何“工作”。构造函数中的工作实际上应该是链接对象引用。这将允许您通过连接模拟类来对此类进行单元测试。
试试这个:
Ideally you should not be doing any "work" in the constructor. Work in the constructor should really be linking up object references. This would allow you to unit test this class by hooking up mock classes instead.
Try this instead:
看起来你什么都不用做。
如果您的构建过程被中断,则不会创建资源。在大多数使用场景中(这位于类之外),Dispose() 永远不会被调用。但即使是这样,您的
if (db != null)
代码也足以起到保护作用。一些小要点:
db = null;
毫无意义。InsertRecord()
应该首先检查if (db != null)
It looks like you don't have to do anything.
If your construction process is interrupted the resource is not created. In most usage scenarios (this lays outside your class), the Dispose() will never be called. But even when it is, your
if (db != null)
code is enough of a guard.A few minor points:
db = null;
inside Dispose() is pointless.InsertRecord()
should start by checkingif (db != null)
您应该只捕获您可以处理的异常。从代码来看,初始化变量 db 可能表明与数据库服务器通信存在问题。
我的建议是按原样保留代码并在中心位置处理异常,例如 Global.asax 中的 Application_Error 事件或初始化 CommissionModel 的事件。
You should only catch exceptions that you can handle. From the code, it appears that initializing the variable db may show that there is a problem communicating with your database server.
My suggestion is to leave your code as is and handle exceptions in a central location such as the Application_Error event in the Global.asax or the event that is initializing the CommissionModel.
如果在构造函数获取资源和将资源返回到应用程序之间不可能发生异常(*),则无需担心。
如果在这种情况下可能会发生异常,我建议采用如下模式:
(*) 如果某个卑鄙的食人魔在您的代码上调用 Tread.Abort,则几乎总是有可能发生 ThreadAbortException,但实际上没有什么可做的无论如何,我们已经做到了这一点。
If there is no way that an exception can occur(*) between the time the constructor acquires a resource and the time it gets returned to the application, there's nothing to worry about.
If it's possible than an exception might occur in such circumstances, I would suggest a pattern like:
(*) It's almost always possible for a ThreadAbortException to occur if some mean nasty ogre calls Tread.Abort on your code, but there's really nothing to be done about that in any case.