Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 14
  1. #1

    discriminare chiamate a metodi

    ciao a tutti,
    ho un classe derivata da TStringList

    codice:
    type mia_classe = class (TStringList)
    ...
    
    
    
    procedure mia_classe.Free
    var
      FileLog : TextFile;
    begin
      
      // prima di liberare la memoria faccio un log  
      AssignFile(FileLog, 'log/mio_log.log');
      
      // vorrei appendere i miei dati ma il compilatore cerca di richiamare
      // il metodo membro di TStringList Append  
      Append(FileLog);
    
      WriteLn(FileLog, thr_web_msg);
      CloseFile (FileLog);
    
      // ok vai al metodo del genitore
      inherited;
    
    end;
    come ho messo nel commento il compilatore mi dà errore quando cerco di chiamare il metodo Append per appendere i dati al file aperto FileLog, mentre logicamente ReWrite(FileLog) funziona correttamente.
    Come faccio a chiamare la funzione Append??

    grazie a tutti
    sergio

  2. #2
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296

    Re: discriminare chiamate a metodi

    Originariamente inviato da mondobimbi
    come ho messo nel commento il compilatore mi dà errore quando cerco di chiamare il metodo Append per appendere i dati al file aperto FileLog, mentre logicamente ReWrite(FileLog) funziona correttamente.
    Come faccio a chiamare la funzione Append??
    Fai precedere al nome della procedura Append la unit in cui è definita questa funzione, cioè System.

    codice:
    System.Append(FileLog);
    Ad ogni modo, io non introdurrei simili operazioni all'interno di un metodo che viene richiamato quando un oggetto viene distrutto: si rischia di compromettere la corretta distruzione dello stesso in caso di errore od eccezione.

    In secondo luogo, il metodo Free non è virtuale, pertanto non può essere ridefinito nelle classi discendenti: eventuali deinizializzazioni vanno inserite nel metodo Destroy che è il metodo da ridefinire ed è preposto a questa funzione.

    Non si tratta solo di una convenzione, ma vi sono anche motivi pratici per cui si segue questa strada.

    Inoltre, non puoi garantire che la tua implementazione venga richiamata, proprio perché il metodo Free non è virtuale e non può essere ridefinito (al contrario del metodo Destroy): se un oggetto appartenente alla classe che hai creato viene assegnata ad una variabile di tipo TStringList o appartenente a qualsiasi classe da cui discende la tua, chiamando il metodo Free attraverso quel riferimento non viene eseguito il tuo codice, bensì quello della classe base in cui viene introdotto tale metodo.

    Insomma, al di là del problema riscontrato, la soluzione che hai adottato risulta "fumosa" sotto molti punti di vista secondo i canoni convenzionali e funzionali della programmazione Delphi.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  3. #3
    grazie dell'indicazione.

    Ci ho lavorato un po' per trovare quale fosse la strada giusta per assicurarmi che tutto fosse rilasciato nella maniera corretta, il meglio che ho pensato è di inserire tutto nel metodo Free, anche perchè, per abitudine, così libero gli oggetti.
    Ti posto il codice della procedura Free della classe TTBase deriva da TXML che deriva da TStringList.
    Implementa la creazione di una pagina xml che viene appunto scritta su un file testo quando viene chiamata la procedura Free e trasferita in remoto.

    codice:
    procedure TTBase.Free;
    var
      nome_file : string;
      locale_adr, remote_adr : string;
      host, user, psw : string;
      res : boolean;
    begin
    
       // lo preleva dalle impostazioni
       locale_adr      := SetLocaleAdrMacro(IniFile.ReadString('Indirizzi Fisici', 'Root', ''));
    
       with DominiTbl do
       begin
    
            remote_adr    := FieldByName('adr_root');
            remote_adr    := SetRemoteAdrMacro(fDominio, remote_adr);
    
            host  := FieldByName('ftp_host');
            user  := FieldByName('ftp_user');
            psw   := FieldByName('ftp_password');
    
       end;
    
    
       nome_file := GetFileName;
       SaveToFile(locale_adr + '/' + nome_file);
    
       res := FtpPutFile(host, '21', remote_adr + '/' + nome_file, locale_adr + '/' + nome_file, User, psw);
    
       with TLogFile.Create ('gesti.log') do
       begin
    
         if not res then
           Write('non è stato possibile trasferire il file ' + nome_file)
         else
           Write('file ' + nome_file + ' correttamente trasferito via ftp');
    
         Free;
    
       end;
    
       with DominiTbl do Free;
    
       inherited;
       
    end;
    in questa modo sono sicuro che quando libero la memoria di un oggetto derivato il tutto mi viene scritto su disco e trasferito in remoto semplicamente scrivento oggett.Free.

    Una classe figlia che implementa un layout a tre colonne ha il metodo Free

    codice:
    procedure TLAY3.Free;
    begin
    
      Current := 'inside_sx';
      AddChild('div');
      Attributo('class', 'clear');
      AddContent('');
    
      Current := 'inside_dx';
      AddChild('div');
      Attributo('class', 'clear');
      AddContent('');
    
      Current := 'content_tag';
      AddChild('div');
      Attributo('class', 'clear');
      AddContent('');
    
      Current := 'innerColumnContainer';
      AddChild('div');
      Attributo('class', 'clear');
      AddContent('');
    
    
      inherited;
    
    end;
    l'inherited finale mi assicura che tutta la catena venga eseguita prima della distruzione dell'oggetto.

    Se ti sembra che sia poco sicuro potrei provare a spostare il codice in Destroy.
    ciao e grazie
    sergio

  4. #4
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    Originariamente inviato da mondobimbi
    grazie dell'indicazione.
    Non so a cosa sia dovuto il ringraziamento... nel tuo codice, non c'è una sola cosa che rispecchi quanto ti ho detto nel messaggio precedente.
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  5. #5
    era per il System.Append
    ciao

  6. #6
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    Originariamente inviato da mondobimbi
    era per il System.Append
    Non ti seguo più...

    Mi riferivo a quanto ho scritto in merito a
    • se possibile, non si introduce "business logic" in distruzione, altrimenti si rischia di non poter distruggere l'oggetto a causa di eccezioni;
    • non si implementa la distruzione nel metodo Free, ma in Destroy, in caso contrario si rischia che il metodo Free non venga chiamato (l'override di Destroy è possibile proprio per questo motivo).


    Introdurre finalizzazioni all'interno del metodo Free, tenuto conto dei meccanismi di funzionamento della libreria VCL e del linguaggio, è errato.
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  7. #7
    scusami ma mi ci devo pensare un pochino.

    In realtà era mia intenzione inserire nel metodo Free non la distruzione degli oggetti (che concettualmente, hai ragione, vanno nel metodo Destroy) ma un insieme di operazioni comuni a tutti gli oggetti derivati: in questo caso inserimento di tag conclusivi in pagine xhtml, scrittura del file su disco ed eventualmente trasferimento in remoto via ftp. La catena delle chiamate a Free si sussegue ordinatamente come da me pensato dall'ultimo figlio a scendere fino all'antenato più lontano, questo lo ho verificato con il debugger. Mai la catena si è interrotta e la chiamata è stata fatta direttamente ad un genitore.

    Per quanto riguarda la gestione delle eccezioni sebbene io non lo abbia fatto è possibile implementarlo tranquillamente in Free e chiuderlo nel blocco con un finally inherited; che passa la palla al Free del genitore e a crescere in una catena di Free e Destroy.

    ciao
    sergio

  8. #8
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    Originariamente inviato da mondobimbi
    La catena delle chiamate a Free si sussegue ordinatamente come da me pensato dall'ultimo figlio a scendere fino all'antenato più lontano, questo lo ho verificato con il debugger. Mai la catena si è interrotta e la chiamata è stata fatta direttamente ad un genitore.
    Per forza: non hai verificato il caso specifico che dà luogo a questo effetto collaterale.

    Prova questo codice:

    codice:
    var
      Obj: TObject;
    
      Obj := TTBase.Create;
    
      // ...
    
      Obj.Free;
    Vedrai che la chiamata al metodo Free non esegue il tuo codice, poiché il metodo Free non va modificato e non va reintrodotto, ma è necessario fare l'override del metodo Destroy.

    A parte tutto, io non capisco quale sia il problema nello spostare il codice da Free a Destroy... certo, a meno che tu non voglia ritrovarti con effetti collaterali e problemi in più rispetto a quelli che dovrebbe normalmente risolvere il software. :master:
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  9. #9
    questa è la procedura che utilizzo per la generazione di una pagina web.
    I dati relativi alla pagina sono nel database (mysql, TmyQuery è una classe che agisce direttamente sulle API), la struttura è invece nelle classi.
    Il costruttore organizza la struttura, la procedura Free inserisce codici di finalizzazione.
    Le procedure Free sono chiamate a scendere attraverso la chiamata ad inherited fino al progenitore che è TStringList.
    La chiamata a Free di TStringList, come classe vcl, chiama alla fine della catena Destroy, che essendo virtuale è il Destroy dell'oggetto creato (nel mio caso della classe TLAY3_ECOM) che non ho bisogno di chiamare direttamente appunto perchè virtuale, e poi a scendere disciplinatamente attraverso le classi genitrici.

    codice:
    procedure genera_pagina_new (dominio, pagina : string);
    var
      tipo : string;
    begin
    
      with TmyQuery.Create do
      begin
    
           SQL.Add('select tipo from PagineSito');
           SQL.Add('where dominio="' + dominio + '"');
           SQL.Add('and pagina="' + pagina + '"');
    
           Open;
    
           // tipo pagina web: html, php
           if not (Eof and Bof) then
             tipo := FieldByName('tipo')
           else tipo := 'html';
    
           Free;
    
      end;
    
      with TLAY3_ECOM.Create (dominio, pagina, '/' + pagina + '.' + tipo) do Free;
    
    end;
    Il tutto mi funzione perfettamente con l'accortezza sempre di inserire inherited alla fine di ciascuna procedura Free, altrimenti la catena si interrompe.

    Una osservazione, questo codice è Free Pascal e lo utilizzo su Lazarus, non so se il comportamente in Delphi possa essere differente, ma non penso.

    Il fatto che ho utilizzato la procedura Free (che comunque nella classe base vcl chiama Destroy) e perchè ho qui inserito del codice di finalizzazione, mentre il codice relativo alla distruzione di eventuali oggetti creati all'interno della classe ho cercato di inserirlo in Destroy.

    ti ringrazio della opportunità che hai colto di chiarimento di un argomento di logica base che non è sempre facile aver l'ocasione di poter discutere

    ciao
    sergio

  10. #10
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    Originariamente inviato da mondobimbi
    Il fatto che ho utilizzato la procedura Free (che comunque nella classe base vcl chiama Destroy) e perchè ho qui inserito del codice di finalizzazione, mentre il codice relativo alla distruzione di eventuali oggetti creati all'interno della classe ho cercato di inserirlo in Destroy.
    Penso che ripetere per l'ennesima volta che *NON* si deve "reintrodurre" il metodo Free ma al contrario ridefinire il metodo Destroy poiché virtuale e richiamato qualunque sia il tipo della variabile che contiene il riferimento all'oggetto da distruggere potrebbe essere colto come una presa in giro, visto che l'ho scritto già mille volte. Quindi, diciamo che ci rinuncio.

    Originariamente inviato da mondobimbi
    ti ringrazio della opportunità che hai colto di chiarimento di un argomento di logica base che non è sempre facile aver l'ocasione di poter discutere
    Non è per essere presuntuoso, ma non credo che la discussione e i chiarimenti che ho portato abbiano trovato un tuo grande interesse: sin dalla prima risposta, ho cercato di darti vari suggerimenti motivandoli per altro in modo tecnico, portando esempi, ma sono stati ogni volta ignorati, come se avessi confermato che la strada che hai scelto fosse corretta.

    Non capisco quindi, onestamente, da dove arrivi il tuo ringraziamento per aver discusso di una cosa che, dopo tanti messaggi, nella tua soluzione finale hai ignorato, come se nessuno avesse mai detto il contrario. E' una logica che mi risulta alquanto oscura, ma contento tu...
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.