嗨,什么是最好的方式来做到嵌套的尝试和最后的语句,在德尔菲?

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    cds3  : TClientDataSet;
    cds4  : TClientDataSet;
begin
  cds1      := TClientDataSet.Create(application );
  try
    cds2      := TClientDataSet.Create(application );
    try
      cds3      := TClientDataSet.Create(application );
      try
        cds4      := TClientDataSet.Create(application );
        try
        ///////////////////////////////////////////////////////////////////////
        ///      DO WHAT NEEDS TO BE DONE
        ///////////////////////////////////////////////////////////////////////
        finally
          cds4.free;
        end;

      finally
        cds3.free;
      end;
    finally
      cds2.free;
    end;
  finally
    cds1.free;
  end;
end;

你可以建议一个更好的方式这样做?

有帮助吗?

解决方案

如何大约如下:

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    cds3  : TClientDataSet;
    cds4  : TClientDataSet;
begin
  cds1      := Nil;
  cds2      := Nil;
  cds3      := Nil;
  cds4      := Nil;
  try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);
    cds3      := TClientDataSet.Create(nil);
    cds4      := TClientDataSet.Create(nil);
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    freeandnil(cds4);
    freeandnil(cds3);
    freeandnil(cds2);
    freeandnil(Cds1);
  end;
end;

这使它紧凑,只有试图免费的情况下,其创建的。真的没有必要执行的筑巢,因为任何失败将导致降到最后和执行所有清理在例如你提供的。

亲我试着不要窝在同一方法...除正在尝试/try/except/最终方案。如果我发现自己需要的巢,然后到我那是一个伟大的时间来认为重构成另一种方法的呼吁。

编辑 清洗了一下谢谢你的意见 mghie史以来色调.

编辑 改变的目的创造,不准申请,如其没有必要在这个例子。

其他提示

我会使用这样的:

var
  Safe: IObjectSafe;
  cds1 : TClientDataSet;
  cds2 : TClientDataSet;
  cds3 : TClientDataSet;
  cds4 : TClientDataSet;
begin
  Safe := ObjectSafe;
  cds1 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds2 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds3 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds4 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  ///////////////////////////////////////////////////////////////////////
  ///      DO WHAT NEEDS TO BE DONE
  ///////////////////////////////////////////////////////////////////////

  // if Safe goes out of scope it will be freed and in turn free all guarded objects
end;

有关该接口的实现见这个的文章,但你可以很容易地创建类似的东西你自己

修改

我只注意到的是,在连接的物品保护()是一个程序。在我自己的代码,我重载返回TObject的,上面的示例代码假设类似的东西卫队()函数。当然,与仿制药获得更好的代码,现在可以...

修改2:

如果你想知道为什么尝试......终于完全在我的代码删除:这是不可能去除嵌套块,而不会引入内存泄漏的可能(当析构函数抛出异常)或访问冲突。因此,最好使用一个辅助类,让接口的引用计数接管完全。助手类可以释放它看守的对象,即使一些析构函数抛出异常。

有没有的嵌套的try代码的另一个变化......终于知道刚刚发生在我身上。如果你没有创建设置为无构造函数的参数AOwner的组件,那么你可以简单地利用生命周期管理的VCL为您提供免费的:

var
  cds1: TClientDataSet;
  cds2: TClientDataSet;
  cds3: TClientDataSet;
  cds4: TClientDataSet;
begin
  cds1 := TClientDataSet.Create(nil);
  try
    // let cds1 own the other components so they need not be freed manually
    cds2 := TClientDataSet.Create(cds1);
    cds3 := TClientDataSet.Create(cds1);
    cds4 := TClientDataSet.Create(cds1);

    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////

  finally
    cds1.Free;
  end;
end;

我在小码大的信徒(如果它不是太模糊)。

如果你想走这(IMO)丑路线,你至少必须保证你不会让一个例外,在析构函数从释放防止一个(组初始化为零知道是否需要释放处理)你的对象的其余部分。点击 是这样的:

function SafeFreeAndNil(AnObject: TObject): Boolean;
begin
  try
    FreeAndNil(AnObject);
    Result :=  True;
  except
    Result := False;
  end;
end;

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    IsOK1 : Boolean;
    IsOK2 : Boolean;
begin
  cds1      := Nil;
  cds2      := Nil; 
 try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);    
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    IsOk2 := SafeFreeAndNil(cds2);    // an error in freeing cds2 won't stop execution
    IsOK1 := SafeFreeAndNil(Cds1);
    if not(IsOk1 and IsOk2) then
      raise EWhatever....
  end;
end;

有是在例外

它显示了一些很好的例子如:

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
begin
  cds1      := Nil;
  cds2      := Nil; 
 try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);    
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    freeandnil(cds2);    //// what has if there in an error in the destructor of cds2
    freeandnil(Cds1);
  end;
end;

什么东西有,如果有在CDS2的析构函数的误差

<强> CDS1不会被破坏

修改

另一个好的资源是:

吉姆McKeeth在代码范围上延迟的异常处理优良视频III被他谈到的问题在最后块处理异常。

@mghie:Delphi的已得到堆栈分配的对象:

type
  TMyObject = object
  private
    FSomeField: PInteger;
  public
    constructor Init;
    destructor Done; override;
  end;

constructor TMyObject.Init;
begin
  inherited Init;
  New(FSomeField);
end;

destructor TMyObject.Done;
begin
  Dispose(FSomeField);
  inherited Done;
end;

var
  MyObject: TMyObject;

begin
  MyObject.Init;
  /// ...
end;

不幸的是,如上面的例子所示:堆栈分配的对象不防止内存泄漏

因此,这仍然需要以这样的析构函数的调用:

var
  MyObject: TMyObject;

begin
  MyObject.Init;
  try
    /// ...
  finally
    MyObject.Done;
  end;
end;

OK,我承认这一点,这是非常接近题外话,但我想,既然堆栈分配的对象是作为一个解决方案中提到(他们是不是如果没有自动析构函数调用),它可能是在这种情况下有趣。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top