resource-cleanup 使用 IDispose 接口来表示:当某个对象不再需要时,它的资源或其他程序状态需要被释放或重置(而且依赖垃圾回收器无法实现这一点,也无法提供所需的控制程度),而 IDisposable.Dispose() 方法就是执行这类清理操作的自然位置。
还有一种结构,即 using 块,它从调用方的角度出发,把所有资源生命周期管理集中到一条语句里。
using (var file = new File("my_secrets"))
{
file.WriteSecret("xxxxxxx");
}
在上面的例子中,退出 using 块时,与 file 关联的文件系统资源会被交还给操作系统释放。
要让这个模式生效,using 语句中的变量必须是实现了 IDisposable 接口的引用类型,并且必须在它的 Dispose() 方法中释放资源、重置程序状态。
C# 8 对该模式做了一处改进:using 语句可以放在代码块的开头。
using var drawingResource = some_provided_or_new_object;
try
{
drawingResource.DrawSomething();
}
catch (Exception)
{
throw;
}
Java 开发者可能认出,这类似于 Java 7 引入的_自动资源管理_机制。
你又回来继续开发在object-relational-mapping中介绍过的 ORM(对象关系映射)系统了。
我们对 ORM 的使用情况分析显示,95% 的事务都是在同一个调用方法内部执行的,因此我们决定,改用单个 ORM 方法来开启、写入并提交事务会更合适。
该数据库有以下实例方法:
Database.BeginTransaction()开启数据库上的一个事务。Database.Write(string data)在事务中把数据写入数据库。如果收到无效数据,就会抛出异常。如果在尚未调用BeginTransaction()的情况下尝试调用这个方法,也会抛出异常。如果成功,数据库的内部状态会变为DataWritten。Database.EndTransaction()把事务提交到数据库。如果无法关闭事务,或者之前没有调用过Database.BeginTransaction(),它可能会抛出异常。Database.Dispose()会清理数据库。这会把数据库的状态变为Closed。实现Orm.Write()方法,开启一个数据库事务,写入传入的数据,然后提交事务。所有异常,包括InvalidOperationException,都应原样传递给调用方,不要记录日志,也不要进行任何其他干预。
Database db = new Database();
Orm orm = new Orm(db);
orm.Write("good write");
// => database has an internal state of State.Closed
orm.Write("bad write");
// => an exception is thrown but database is left with an internal state of State.Closed
orm.Write("bad commit");
// => an exception is thrown but database is left with an internal state of State.Closed
Orm.Write()推出已经几个月了,团队内部出现了分歧。许多开发者希望 ORM 在抛出异常时处理错误,并直接向调用方返回一个成功与否的指示。
请实现Orm.WriteSafely()方法,开启一个数据库事务,写入传入的数据并提交事务(同上)。如果写入成功,它应返回true,否则返回false。不要尝试记录异常日志。
Database db = new Database();
Orm orm = new Orm(db);
orm.WriteSafely("good write");
// => true
orm.WriteSafely("bad write");
// => false
orm.WriteSafely("bad commit");
// => false