我也写了一个这样的东西,先是代码:
unit uScopeGuard;
interface
uses
  SysUtils, Classes, Contnrs;
type
  TShenMethod = record
    Code, Sender, Data: Pointer;
    T: Integer;
  end;
  TShenMethodDynArray = array of TShenMethod;
  TObjProcedure = procedure (Sender: TObject);
  TObjectGuard = class;
  IScopeGuard = interface
  ['{7561A2E9-F368-429F-9982-BCFFACC32573}']
    function CreateObject(AObject: TObject): TObject;
    function CreateSubScopeGuard: IScopeGuard;
    procedure Add(AObject: TObjectGuard);
    procedure Clear;
    procedure DismissAll;
    procedure Remove(AObject: TObjectGuard);
  end;
  TScopeGuard = class(TInterfacedObject, IScopeGuard)
  private
    FStack: TStack;
  protected
    procedure Clear; virtual;
  public
    constructor Create;
    destructor Destroy; override;
    function CreateObject(AObject: TObject): TObject;
    function CreateSubScopeGuard: IScopeGuard;
    procedure Add(AObject: TObjectGuard);
    procedure DismissAll;
    procedure Remove(AObject: TObjectGuard);
  end;
  TObjectGuard = class
  private
    FDismiss: Boolean;
  protected
    FMethods: TShenMethodDynArray;
    constructor InternalCreate;
    procedure AddMethods(M: TShenMethodDynArray); virtual;
  public
    constructor Create;
    destructor Destroy; override;
    procedure CleanUp; virtual;
    procedure Dismiss;
  end;
  TObjectGuardFactory = class
  public
    class function Make(M: TShenMethod): TObjectGuard; overload;
    class function Make(M: array of TShenMethod): TObjectGuard; overload;
  end;
  ISG = IScopeGuard;
  TSG = TScopeGuard;
  TOG = TObjectGuard;
  TOGF = TObjectGuardFactory;
function MakeMethod(const Code: PLongint; const Sender: Pointer = nil; const Data: Pointer = nil): TShenMethod; overload;
function MakeMethod(const Code: TProcedure): TShenMethod; overload;
function MakeMethod(const Code: TObjProcedure; const Sender: TObject): TShenMethod; overload;
function MakeMethod(const Code: TNotifyEvent; const Sender, Data: TObject): TShenMethod; overload;
function MakeMethod(const Code: TThreadMethod; const Sender: TObject): TShenMethod; overload;
function MakeFreeAndNil(var P): TShenMethod;
function MakeAssignOrd(var Dest; const Src: Integer): TShenMethod;
function MakeAssignStr(var Dest: string; const Src: string): TShenMethod;
procedure CallMethod(const M: TShenMethod); overload;
implementation
const
  SMNormal = 0;
  SMFreeAndNil = 1;
  SMAssignOrd = 2;
  SMAssignStr = 3;
function MakeMethod(const Code: PLongint; const Sender, Data: Pointer): TShenMethod;
begin
  Result.Code := Code;
  Result.Sender := Sender;
  Result.Data := Data;
  Result.T := SMNormal;
end;
function MakeMethod(const Code: TProcedure): TShenMethod;
begin
  Result := MakeMethod(PLongint(@Code));
end;
function MakeMethod(const Code: TObjProcedure; const Sender: TObject): TShenMethod;
begin
  Result := MakeMethod(PLongint(@Code), Sender);
end;
function MakeMethod(const Code: TNotifyEvent; const Sender, Data: TObject): TShenMethod;
begin
  Result := MakeMethod(PLongint(@Code), Sender, Data);
end;
function MakeMethod(const Code: TThreadMethod; const Sender: TObject): TShenMethod;
begin
  Result := MakeMethod(PLongint(@Code), Sender);
end;
function MakeFreeAndNil(var P): TShenMethod;
begin
  Result.Code := nil;
  Result.Sender := nil;
  Result.Data := @P;
  Result.T := SMFreeAndNil;
end;
function MakeAssignOrd(var Dest; const Src: Integer): TShenMethod;
begin
  Result.Code := nil;
  Result.Sender := Pointer(Src);
  Result.Data := @Dest;
  Result.T := SMAssignOrd;
end;
function MakeAssignStr(var Dest: string; const Src: string): TShenMethod;
begin
  Result.Code := nil;
  Result.Sender := PChar(Src);
  Result.Data := PChar(@Dest);
  Result.T := SMAssignStr;
end;
procedure CallMethodNormal(const M: TShenMethod);
asm
  CMP  M.Code, 0;
  JZ   @@end;
  MOV  ECX, EAX;
  MOV  EAX, [ECX].TShenMethod.Sender;
  MOV  EDX, [ECX].TShenMethod.Data;
  Call [ECX].TShenMethod.Code;
@@end:
end;
procedure CallMethodFreeAndNil(const M: TShenMethod);
begin
  FreeAndNil((M.Data)^);
end;
procedure CallMethodAssignOrd(const M: TShenMethod);
begin
  PLongint(M.Data)^ := Longint(M.Sender);
end;
procedure CallMethodAssignStr(const M: TShenMethod);
var
  s: string;
begin
  s := StrPas(M.Sender);
  PChar((M.Data)^) := PChar(s);
end;
procedure CallMethod(const M: TShenMethod);
begin
  case M.T of
    SMNormal: CallMethodNormal(M);
    SMFreeAndNil: CallMethodFreeAndNil(M);
    SMAssignOrd: CallMethodAssignOrd(M);
    SMAssignStr: CallMethodAssignStr(M);
  end;
end;
{ TScopeGuard }
type TStackAccess = class(TStack);
procedure TScopeGuard.Add(AObject: TObjectGuard);
begin
  FStack.Push(AObject);
end;
procedure TScopeGuard.Clear;
var
  AObject: TObject;
begin
  while FStack.Count > 0 do
  begin
    AObject := FStack.Pop;
    if Assigned(AObject) then
    begin
      AObject.Free;
    end;
  end;
end;
constructor TScopeGuard.Create;
begin
  inherited Create;
  FStack := TStack.Create;
end;
function TScopeGuard.CreateObject(AObject: TObject): TObject;
begin
  Result := AObject;
  Add(TObjectGuardFactory.Make(MakeMethod(Result.Free, Result)));
end;
function TScopeGuard.CreateSubScopeGuard: IScopeGuard;
begin
  Result := TScopeGuard.Create;
end;
destructor TScopeGuard.Destroy;
begin
  Clear;
  FStack.Free;
  inherited;
end;
procedure TScopeGuard.DismissAll;
var
  i: Integer;
  AObject: TObjectGuard;
begin
  with TStackAccess(FStack).List do
  begin
    for i := Count - 1 downto 0 do
    begin
      AObject := Items[i];
      AObject.Dismiss;
    end;
  end;
end;
procedure TScopeGuard.Remove(AObject: TObjectGuard);
begin
  TStackAccess(FStack).List.Remove(AObject); // Do not free AObject
end;
{ TObjectGuard }
procedure TObjectGuard.AddMethods(M: TShenMethodDynArray);
var
  i, OldLen, MLen: Integer;
begin
  MLen := Length(M);
  if MLen > 0 then
  begin
    OldLen := Length(FMethods);
    SetLength(FMethods, OldLen + MLen);
    for i := 0 to MLen - 1 do
    begin
      FMethods[OldLen + i] := M[i];
    end;
  end;
end;
procedure TObjectGuard.CleanUp;
var
  i: Integer;
begin
  for i := 0 to Length(FMethods) - 1 do
  begin
    CallMethod(FMethods[i]);
  end;
end;
constructor TObjectGuard.Create;
begin
  raise Exception.Create('Please use TObjectGuardFactory.make instead of TObjectGuard.Create');
end;
destructor TObjectGuard.Destroy;
begin
  if not FDismiss then CleanUp;
  inherited;
end;
procedure TObjectGuard.Dismiss;
begin
  FDismiss := True;
end;
constructor TObjectGuard.InternalCreate;
begin
  inherited Create;
end;
{ TObjectGuardFactory }
class function TObjectGuardFactory.Make(M: TShenMethod): TObjectGuard;
var
  _M: TShenMethodDynArray;
begin
  Result := TObjectGuard.InternalCreate;
  SetLength(_M, 1);
  _M[0] := M;
  Result.AddMethods(_M);
end;
class function TObjectGuardFactory.Make(M: array of TShenMethod): TObjectGuard;
var
  _M: TShenMethodDynArray;
  I, Count: Integer;
begin
  Result := nil;
  Count := Length(M);
  if Count <= 0 then Exit;
  Result := TObjectGuard.InternalCreate;
  SetLength(_M, Count);
  for I := 0 to Count - 1 do _M[I] := M[I];
  Result.AddMethods(_M);
end;
end.