Gestione errori in VBA



  • Gestione errori in VBA...
    di cromagno data: 24/08/2015 02:43:05

    Chiedo questo perchè per me la cosa più semplice sarebbe gestire gli errori con "On Error GoTo", conoscendo preventivamente quale errore potrebbe presentarsi. Però, mi è stato fatto notare che non sempre è il metodo migliore.
    Trascinando l'esempio sulle "Collection", un classico errore è il 457 (cioè che una chiave è già stata associata ad un elemento di quella Collection - insomma, non ci devono essere duplicati), qual'è il miglior modo per gestire l'errore (soggettivamente parlando) e perchè?

    Grazie in anticipo a chi risponderà



  • di Marius44 data: 24/08/2015 07:25:36

    Ciao Tore
    prova a questi indirizzi:
    h t t p s://support.microsoft.com/kb/142138/it
    h t t p://excelvba.altervista.org/Tutorials/Errori.html
    h t t p://ennius.altervista.org/free/ifvba49.htm
    h t t p://www.html.it/pag/15726/la-gestione-degli-errori-in-visual-basic/

    Ai suggerimenti dati dai guru sopra richiamati aggiungerei - ma è una scelta personale - di evitare "On Error Resume Next" perchè in pratica, non gestendo l'errore, i risultati possono essere imprevedibili.

    Ciao,
    Mario



  • di patel data: 24/08/2015 08:26:59

    nel caso delle collection l'errore è inevitabile, anzi cercato, e quindi conviene usare "On Error Resume Next"





  • di Vecchio Frac data: 24/08/2015 09:03:09

    Cosa intendi con l'avverbio "soggettivamente" nella frase "qual'è il miglior modo per gestire l'errore (soggettivamente parlando)"? Non mi permetterei mai di dirti cosa è meglio per te, solo tu lo sai ^_^





  • di cromagno data: 24/08/2015 10:07:09

    Ciao a tutti,
    Mario, grazie per i links.

    @VF

    si, appunto vorrei sapere per voi (per il vostro "stile") qual'è il modo migliore (o più pratico) per gestire gli errori



  • di Vecchio Frac data: 24/08/2015 13:33:57

    Io personalmente cerco di prevenire gli errori più che di gestirli. Di conseguenza nei miei codici è quasi sempre assente la gestione degli errori. L'unico caso in cui devo usare On Error è la gestione della Collection, ma anche in questo caso preferisco orientarmi sui Dictionary che espongono il comodo metodo .Exists per verificare se un elemento appartiene all'insieme.





  • di scossa data: 24/08/2015 14:13:03

    @cromagno: in questo vecchio post trovi più o meno il mio pensiero:
    gestione degli errori



    scossa's web site
    Se tu hai una mela, ed io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno. Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee.(George Bernard Shaw)



  • di cromagno data: 24/08/2015 18:33:04

    Grazie per le risposte ragazzi
    per mettere "Risolto" aspetto ancora un paio di giorni, magari scrive qualcun'altro...

    Ciao



  • di cromagno data: 25/08/2015 18:47:08

    @Vecchio Frac
    mi è appena capitato di seguire il tuo consiglio, cioè prevenire gli errori...
    Con l'evento Worksheet_Change se si seleziona un range che comprende anche il "target", per cancellare il contenuto, spunta sempre fuori quel fastidioso "Error 13 - Tipo non corrispondente".
    Di solito lo raggiravo con "On Error GoTo" ma cercando nello storico ho trovato proprio una tua discussione sull'argomento, dove proponevi questa "prevenzione":

    If Target.Cells.Count > 1 Then Exit Sub

    perfetto. Era la soluzione che cercavo da tempo



  • di Vecchio Frac data: 25/08/2015 18:53:34

    Mi fa piacere di risultare utile ogni tanto... grazie del riscontro ^_^
    Dovresti anche controllare il caso della cella vuota con "If Trim(Target) = "" then exit sub" che occorre quando si preme Canc sulla cella e che di solito produce effetti indesiderati quando in realtà non si vuole fare proprio niente, tranne cancellare la cella; e non dimenticare di disabilitare gli eventi dentro l'evento Change per non innescare ricorsioni (non ritorsioni ^_^)





  • di cromagno data: 25/08/2015 18:58:29

    Ok...
    grazie per le dritte



  • di scossa data: 25/08/2015 19:41:46

    Giusto per dare il mio contributo.

    cit.: "Di solito lo raggiravo con "On Error GoTo" ma cercando nello storico ho trovato proprio una tua discussione sull'argomento, dove proponevi questa "prevenzione":
    If Target.Cells.Count > 1 Then Exit Sub
    "

    Come già detto nel precedente post, personalmente preferisco gestire tutte le celle del target, od eventualmente, in base al contesto, gestire Target.Cells(1,1), piuttosto che abortire la macro.

    scossa's web site
    Se tu hai una mela, ed io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno. Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee.
    (George Bernard Shaw)



  • di Vecchio Frac data: 25/08/2015 20:20:37

    E se non devi fare niente altro, gestisci comunque il caso con un'uscita senza altre azioni. La macro non si "abortisce" con Exit Sub... termina semplicemente di fare il suo dovere.





  • di scossa data: 25/08/2015 21:24:56

    cit.: "E se non devi fare niente altro, gestisci comunque il caso con un'uscita senza altre azioni."

    Come già detto non amo gli Exit Sub in mezzo al codice, si può ottenere lo stesso comportamento di
    If Target.Cells.Count > 1 Then Exit Sub

    con
    If Target.Cells.Count = 1 Then
    ..... codice normale
    End If

    P.S.: effettivamente il termine "abortire" non è corretto, dovevo usare "interrompere"


    scossa's web site
    Se tu hai una mela, ed io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno. Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee.
    (George Bernard Shaw)


  • IMHO
    di scossa data: 26/08/2015 09:04:24

    cit.: "La macro non si "abortisce" con Exit Sub... termina semplicemente di fare il suo dovere."

    Vorrei condividere solo un'ultima considerazione.

    La conclusione "naturale" di una sub (come di una Function) è l'esecuzione dell'istruzione End Sub.
    L'istruzione Exit Sub non causa un "salto" ad End Sub ma la interrompe "brutalmente". Poco cambia direte voi, però, personalmete, trovo la creazione di "arbitrari" punti di uscita dal codice non raccomandabile, anche perché facilmente evitabile.


    scossa's web site
    Se tu hai una mela, ed io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno. Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee.(George Bernard Shaw)




  • di Vecchio Frac data: 26/08/2015 10:40:41

    Sì, la conclusione naturale di una procedura è "End procedura". però non mi risulta che Exit ne causi l'interruzione brutale (il che sarebbe un aborto della procedura come dicevi ieri), ma ne rappresenta un punto di uscita anticipato. Addirittura necessario quando hai una gestione degli errori con etichetta a fine procedura che altrimenti verrebbe eseguita.
    Non vorrei dire una cavolata (e mi aspetto che mi correggi) ma probabilmente Exit Sub richiama comunque il garbage collector prima di uscire, cosa che "End" da solo non fa.
    Questo tanto per fare la punta alle matite :)
     
    Sub test()
    dim o as object
    
      On Error Goto gest_err
    
      set o = createobject("word.application")
      o.documents.open "my document.docx"  
    
    exit_here:
      o.close false
      o.quit
    
      Exit Sub   '<<< qui serve!!
    
    gest-err:
      MsgBox Err.Description  
      Resume exit_here
    End Sub






  • di scossa data: 26/08/2015 11:40:46

    cit.: "Addirittura necessario quando hai una gestione degli errori con etichetta a fine procedura che altrimenti verrebbe eseguita"

    Il codice che proponi presenta il solito problema del continuo rimando all'etichetta exit_here in caso di errore nella creazione dell'oggetto o, o nell'apertura del file (o.close solleverebbe nuovamente l'errore se o non fosse stato creato e o.documents.Close solleverebbe un nuovo errore se o.Open fosse fallita).
    Mi sembra una "logica" molto debole.

    Il codice sotto mi sembra molto più solido, ed il suo flusso molto più lineare e comprensibile.
    Poi ognuno è libero di gestire gli errori come vuole, come dice il proverbio "... i cocci sono suoi"


    scossa's web site
    Se tu hai una mela, ed io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno. Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee.(George Bernard Shaw)

     
    Sub test_2()
      Dim o As Object
      Dim oDoc As Object
      
      On Error GoTo gest_Err
    
    	'istruzioni senza errori
      Set o = CreateObject("word.application")
    	Set oDoc = o.documents.Open("documento esistente.doc")
    	
    	'istruzioni per generare errori da scambiare con le rispettive precedenti
    	'Set o = CreateObject("wordA.application") 'errore ActiveX
    	'Set oDoc = o.documents.Open("documento_inesistente.doc")
    
      o.Visible = True
      
    gest_Err:
      If Err.Number <> 0 Then
        MsgBox Err.Description
      End If
      If Not oDoc Is Nothing Then oDoc.Close
      If Not o Is Nothing Then o.Quit
      Set o = Nothing
    End Sub



  • di scossa data: 26/08/2015 11:52:50

    Dimenticato
    Set oDoc = Nothing

    scossa's web site
    Se tu hai una mela, ed io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno. Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee.
    (George Bernard Shaw)

     
    Sub test_2()
      Dim o As Object
      Dim oDoc As Object
      
      On Error GoTo gest_Err
    
    	'istruzioni senza errori
      Set o = CreateObject("word.application")
    	Set oDoc = o.documents.Open("documento esistente.doc")
    	
    	'istruzioni per generare errori da scambiare con le rispettive precedenti
    	'Set o = CreateObject("wordA.application") 'errore ActiveX
    	'Set oDoc = o.documents.Open("documento_inesistente.doc")
    
      o.Visible = True
      
    gest_Err:
      If Err.Number <> 0 Then
        MsgBox Err.Description
      End If
      If Not oDoc Is Nothing Then oDoc.Close
      If Not o Is Nothing Then o.Quit
      Set o = Nothing
      Set oDoc = Nothing
    End Sub