Question

Salut Quelle est la meilleure façon de le faire essayer emboîtée & finally dans delphi?

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;

Pouvez-vous suggérer une meilleure façon de le faire?

Était-ce utile?

La solution

comment sur les points suivants:

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;

maintient compact et tente seulement de libérer les instances qui ont été créées. Il n'y a vraiment pas besoin d'effectuer l'imbrication puisque tout échec entraînera la chute et enfin effectuer toutes le nettoyage dans l'exemple que vous avez fourni.

Personnellement, j'essaie de ne pas se nicher dans le même méthode ... à l'exception d'un essai / try / except / scénario finalement. Si je me trouve avoir besoin de nid, alors pour moi qui est un grand temps de penser refactorisation dans un autre appel de méthode.

EDIT Nettoyé un peu grâce aux commentaires par mghie et utku .

EDIT a changé la création d'un objet pour ne pas faire référence à l'application, comme pas nécessaire dans cet exemple.

Autres conseils

J'utiliser quelque chose comme ceci:

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;

Pour la mise en œuvre de l'interface voir cet article , mais vous pouvez facilement créer quelque chose de similaire vous .

EDIT:

Je viens de remarquer que, dans la garde d'article lié () est une procédure. Dans mon code, j'ai surchargé les fonctions qui renvoient TObject, au-dessus exemple de code Guard () suppose quelque chose de similaire. Bien sûr, avec beaucoup génériques meilleur code est maintenant possible ...

EDIT 2:

Si vous vous demandez pourquoi essayer ... est finalement complètement retiré dans mon code: Il est impossible de supprimer les blocs imbriqués sans introduire la possibilité de fuites de mémoire (lorsque des exceptions soulèvent Destructeurs) ou violations d'accès. Par conséquent, il est préférable d'utiliser une classe d'aide, et laisser le comptage de référence des interfaces prendre en charge complètement. La classe d'aide peut libérer tous les objets qu'il gardes, même si certains des exceptions Destructeurs soulèvent.

Il y a une autre variante du code sans essayer imbriqué ... enfin que vient de se produire pour moi. Si vous ne créez pas les composants avec le paramètre AOwner du constructeur mis à zéro, alors vous pouvez simplement utiliser la gestion de la vie que la VCL vous donne gratuitement:

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;

Je suis un grand croyant dans un petit code (si elle est pas trop brouillées).

Si vous voulez aller dans cette (OMI) la route laide (manipulation avec initialisation groupe à zéro pour savoir si est nécessaire libération), vous au moins doit garantir que vous ne laisserez pas une exception dans l'un des destructor empêcher de libérer le reste de vos objets.
Quelque chose comme:

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;

Il y a une bonne vidéo sur dans les constructeurs et destructeurs

Il montre quelques beaux exemples tels que:

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;

Ce qui a s'il y a une erreur dans la destructor de cds2

Cds1 ne sera pas détruit

EDIT

Une autre bonne ressource est:

Jim McKeeth excellente vidéo sur Delayed de traitement des exceptions dans la plage de codes III ont été, il parle de problèmes à la gestion des exceptions dans le bloc finally.

@mghie: Delphi a obtenu empiler des objets alloués:

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;

Malheureusement, comme l'exemple ci-dessus montre:. Les objets attribués Stack n'empêchent pas les fuites de mémoire

Donc, ce serait encore besoin d'un appel à la destructor comme ceci:

var
  MyObject: TMyObject;

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

OK, je l'avoue, cela est presque hors sujet, mais je pense qu'il pourrait être intéressant dans ce contexte car la pile des objets attribués ont été cités comme une solution (qui ne sont pas s'il n'y a pas d'appel de destructor automatique).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top