Dai un'argumentexception o argomentazione di nullexception da metodi privati?


20

Stavo solo rivedendo un po 'di codice che ho scritto qualche tempo fa, e posso vedere che ho un paio di metodi privati ​​che generano argomentonullexceptions e / o argumentexceptions se ci sono problemi con i parametri dei metodi.

Immagino che la mia logica sia che aiuta a provare l'applicazione in futuro se qualcuno tenta di "abusare" del metodo in futuro. Tuttavia, dato che si tratta di un metodo privato e le persone che probabilmente chiamano questo metodo possono vedere i commenti e il codice associati, non è necessario lanciarlo. Certamente non fa male averli, anche se aggiunge disordine.

La mia sensazione è che queste eccezioni siano generalmente più utili su qualcosa come un'API che verrà esposta pubblicamente.

Risposte:


22

Normalmente, per i metodi privati ​​non si generano eccezioni poiché, come è stato scritto, lo sviluppatore dovrebbe sapere come e da dove chiama il metodo. Pertanto, le variabili passate come parametri al metodo privato devono essere controllate al di fuori del metodo, ovvero prima di chiamarlo. Lanciare "InvalidArgumentException" e altre eccezioni simili è considerata una buona pratica per i metodi pubblici (sia che tu stia scrivendo o meno "API").

Per quei casi in cui si desidera lanciare "InvalidArgumentException", vale la pena ricordare che esiste una Assertclasse nell'API Spring per Java dalla versione 1.1.2. È stato molto utile - almeno per me - scrivere meno codice per eseguire i controlli.

È tuttavia possibile utilizzare "assert" per verificare i parametri in metodi privati. Questo è uno dei loro veri scopi. Sono più motivi per usarli, controlla il seguente link che spiega anche quando usare gli assert e quando usare le eccezioni. Gli asserti non devono essere inclusi nel codice di produzione e il compilatore li rimuove per impostazione predefinita. Quindi sono quello che stai cercando: aiutare gli sviluppatori, invisibile per gli utenti. In Java devi usare un flag speciale ("-ea") per dire al compilatore di abilitare le asserzioni. Puoi considerarli come amici di "debug".

Ecco come utilizzare gli asserti in:


1
Apache Commons ha anche una classe Convalida che funziona in modo simile alla classe Assert di Spring
Rosa Richter,

@cantido yes e aggiungerei anche la classe Preconditions in Guava di Google che funziona allo stesso modo. Grazie per l'informazione :-)
Jalayn

2

Come tutto il resto dipende ....

Se i metodi pubblici sono semplici wrapper che chiamano il metodo privato (sulla falsariga di un metodo di sovraccarico privato), può avere senso gettare un'eccezione nel metodo privato invece di archiviarne uno pubblico.

Generalmente se non soddisfa la definizione di cui sopra, di solito non vorrei controllare gli argomenti / lanciare un'eccezione su un metodo privato. Sebbene ci siano altri casi in genere lo faccio in un metodo privato prima di eseguire un'operazione costosa che potrebbe non riuscire a metà se gli argomenti non sono validi.


2

Mi rendo conto che sebbene la domanda non abbia alcun tag di lingua, probabilmente sta implicitamente parlando di "lingue del caffè". Ma solo per completezza, vorrei menzionare l'apparente consenso alquanto divergente nel mondo C ++.

Ci sono tre cose a cui i programmatori C ++ saranno generalmente interessati:

  • Avrà overhead zero in build ottimizzate? (Cioè, può essere "compilato"?)
  • Posso usarlo per intercettare un debugger proprio nel punto in cui è stato rilevato l'errore?
  • Posso usarlo per segnalare problemi da funzioni dichiarate noexcept?

In passato, ho affrontato il primo problema scrivendo codice come questo

int
factorial(const int n)
{
  if (CHECK_ARGS)
    {
      if (n < 0)
        throw std::invalid_argument {"n < 0"};
    }
  int fac = 1;
  for (int i = 2; i <= n; ++i)
    fac *= i;
  return fac;
}

dove CHECK_ARGSè #defined una costante di compilazione in modo che il compilatore possa eliminare completamente tutto l'argomento che controlla il codice in build ottimizzate. (Non sto dicendo che la compilazione dei check out sia una buona cosa in generale, ma credo che un utente dovrebbe avere la possibilità di compilarli.)

Mi piace ancora su questa soluzione che l'argomento che controlla il codice sia chiaramente visibile raggruppato insieme nel if. Tuttavia, il secondo e il terzo problema non sono risolti da questo. Pertanto, ora mi sto appoggiando ancora di più all'utilizzo di una assertmacro per il controllo degli argomenti.

Gli standard di codifica Boost concordano con questo:

Che dire degli errori del programmatore?

Come sviluppatore, se ho violato un prerequisito di una libreria che sto usando, non voglio che lo stack si svolga. Quello che voglio è un core dump o l'equivalente - un modo per ispezionare lo stato del programma nel punto esatto in cui è stato rilevato il problema. Questo di solito significa assert()o qualcosa del genere.

C'è stato un discorso molto interessante tenuto da John Lakos a CppCon'14 dal titolo Defensive Programming Done Right ( parte 1 , parte 2 ). Nella prima parte del suo discorso, discute della teoria dei contratti e del comportamento indefinito. Nella seconda parte, presenta quella che considero un'ottima proposta per il controllo sistematico degli argomenti. In sostanza, propone macro di asserzioni che consentono all'utente di selezionare la quantità di budget (in termini di utilizzo della CPU) che è disposta a donare alla biblioteca per la verifica degli argomenti e che la biblioteca fa un uso saggio di quel budget. Inoltre, l'utente può anche installare una funzione di gestione degli errori globale che verrà chiamata in caso di rilevamento di un contratto non funzionante.

Per quanto riguarda l'aspetto che una funzione è privata, non penso che ciò significhi che non dovremmo mai farla controllare i suoi argomenti. Potremmo fidarci maggiormente del nostro codice per non violare il contratto di una funzione interna, ma sappiamo anche che non siamo perfetti. Il controllo degli argomenti nelle funzioni interne è altrettanto utile nel rilevare i nostri bug come nelle funzioni pubbliche per rilevare i bug nel codice client.


1

Considera la seguente struttura:

  1. Logica interna: questa funzione presuppone di essere chiamata con parametri corretti e quindi utilizza assert per verificare precondizioni, postcondizioni e invarianti per verificare la propria logica interna.

  2. Interfaccia utente involucro: Questa funzione include la funzione interna e usa InvalidArgumentExceptions per gestire valori sbagliati e per dire all'utente di correggere i suoi ingressi: Assert(x).hasLength(4);, Assume(y).isAlphanumeric();, Assert(z).isZipCode();, Assume(mailAdress).matchesRegex(regex_MailAdress);, Reject(x).ifEmpty();, etc.

  3. Wrap dell'interfaccia batch: questa funzione racchiude la funzione interna e utilizza la registrazione, i contrassegni di validità e le statistiche per gestire valori errati senza interrompere alcune attività di lunga durata. I contrassegni potrebbero essere utilizzati in seguito da qualcuno che controlla e pulisce il database dei risultati.

  4. Wrapper dell'interfaccia della riga di comando: questa funzione avvolge la funzione interna e chiede di nuovo l'ultimo input.

Dovresti usare entrambi - affermazioni ed eccezioni - in metodi diversi per compiti diversi. È necessario separare la logica interna dal controllo dei parametri. Confrontalo con la separazione di Modello, Vista, Controller.


0

Esistono modi migliori per evitare il controllo di riferimento null: utilizzare il contratto di codice o un framework AOP per eseguire il controllo per te. Google "contratto c # code" o "postsharp".


Immagino che la mia domanda si estenderebbe anche ai contratti di codice. C'è bisogno di verificare i presupposti del metodo in un metodo privato (ad es. Per prove future o impedirti di spararti al piede)?
Mr Moose,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.