提取嵌套的try/finally块

Uli*_*rdt 0 delphi refactoring extract try-finally

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

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;
Run Code Online (Sandbox Code Playgroud)

并想要类似的东西

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;
Run Code Online (Sandbox Code Playgroud)

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

Rob*_*edy 5

关于类的三件事使这个成语变得安全和容易:

  1. 在构造函数的内存分配阶段(在实际构造函数体运行之前),类引用字段初始化为nil.
  2. 当构造函数中发生异常时,将自动调用析构函数.
  3. 调用Free空引用始终是安全的,因此您永远不需要先检查Assigned.

由于析构函数可以依赖所有字段来获取已知值,因此Free无论构造函数在崩溃之前获得多远,它都可以安全地调用所有字段.每个字段将保留一个有效的对象引用,或者它将是nil,无论哪种方式,都可以安全地释放它.

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

destructor TDoSomething.Destroy;
begin
  Resource1.Free;
  Resource2.Free;
  Resource3.Free;
end;
Run Code Online (Sandbox Code Playgroud)

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

Context := TDoSomething.Create;
try
  Context.UseResources;
finally
  Context.Free;
end;
Run Code Online (Sandbox Code Playgroud)