提取嵌套的try/finally块 [英] Extract nested try/finally blocks

查看:169
本文介绍了提取嵌套的try/finally块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您如何将嵌套的try/finally块从例程提取"到可重用的实体中?说我有

How would you "extract" nested try/finally blocks from a routine into a reusable entity? Say I have

procedure DoSomething;
var
  Resource1: TSomeKindOfHandleOrReference1;
  Resource2: TSomeKindOfHandleOrReference2;
  Resource3: TSomeKindOfHandleOrReference3;
begin
  AcquireResource1;
  try
    AcquireResource2;
    try
      AcquireResource3;
      try
        // Use the resources
      finally
        ReleaseResource3;
      end;
    finally
      ReleaseResource2;
    end;
  finally
    ReleaseResource1;
  end;
end;

并想要类似的东西

TDoSomething = record // or class
strict private
  Resource1: TSomeKindOfHandleOrReference1;
  Resource2: TSomeKindOfHandleOrReference2;
  Resource3: TSomeKindOfHandleOrReference3;
public
  procedure Init; // or constructor
  procedure Done; // or destructor
  procedure UseResources;
end;

procedure DoSomething;
var
  Context: TDoSomething;
begin
  Context.Init;
  try
    Context.UseResources;
  finally
    Context.Done;
  end;
end;

我希望它具有与嵌套原件相同的异常安全性.将TDoSomething.Init中的ResourceN变量初始化为零并在TDoSomething.Done中进行一些if Assigned(ResourceN) then检查是否足够?

I want this to have the same exception-safety as the nested original. Is it enough to zero-initialize the ResourceN variables in TDoSomething.Init and do some if Assigned(ResourceN) then checks in TDoSomething.Done?

推荐答案

有关类的三件事使此成语变得安全又简单:

There are three things about classes that make this idiom safe and easy:

  1. 在构造函数的内存分配阶段(在实际构造函数主体运行之前),类引用字段被初始化为nil.
  2. 当构造函数中发生异常时,析构函数将自动被调用.
  3. 在空引用上调用Free始终是安全的,因此您无需先检查Assigned.
  1. During the memory-allocation phase of the constructor (before the real constructor body runs), class-reference fields get initialized to nil.
  2. When an exception occurs in a constructor, the destructor is called automatically.
  3. It's always safe to call Free on a null reference, so you never need to check Assigned first.

由于析构函数可以依赖所有字段具有已知值,因此它可以安全地对所有内容调用Free,而不管构造函数在崩溃前走了多远.每个字段要么保存一个有效的对象引用,要么为nil,无论哪种方式,释放它都是安全的.

Since the destructor can rely on all fields to have known values, it can safely call Free on everything, regardless of how far the constructor got before crashing. Each field will either hold a valid object reference or it will be nil, and either way, it's safe to free it.

constructor TDoSomething.Create;
begin
  Resource1 := AcquireResource1;
  Resource2 := AcquireResource2;
  Resource3 := AcquireResource3;
end;

destructor TDoSomething.Destroy;
begin
  Resource1.Free;
  Resource2.Free;
  Resource3.Free;
end;

以与其他任何类相同的方式使用它:

Use it the same way you use any other class:

Context := TDoSomething.Create;
try
  Context.UseResources;
finally
  Context.Free;
end;

这篇关于提取嵌套的try/finally块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆