Butta un'argumente scetticismo o un'argomentazione dal metodo privato?

18

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

Suppongo che il mio fondamento logico sia quello di aiutare a provare a posteriori l'applicazione se qualcuno tenta di "abusare" del metodo in futuro. Tuttavia, dato che si tratta di un metodo privato e le persone che possono chiamare questo metodo possono vedere i commenti e il codice associati, non è necessario lanciarlo. Certamente non fa male averli, anche se aggiunge confusione.

La mia sensazione è che queste eccezioni siano generalmente più utili su qualcosa di simile a una API che verrà esposta pubblicamente.

    
posta Mr Moose 11.08.2011 - 07:34
fonte

5 risposte

21

Normalmente, per i metodi privati non si generano eccezioni dal momento che come lo hai scritto, lo sviluppatore dovrebbe sapere come e da dove viene chiamato il metodo. Come tale, le variabili passate come parametri al metodo privato dovrebbero essere verificate al di fuori del metodo, cioè prima di chiamarlo. Lanciare "InvalidArgumentException" e altre eccezioni di questo tipo è considerata una buona pratica per i metodi pubblici (sia che si stia scrivendo una "API" o meno).

Per quei casi in cui vuoi lanciare "InvalidArgumentException" vale la pena menzionare che esiste un Assert classe in Spring API per Java dalla versione 1.1.2. È stato molto utile, almeno per me, scrivere meno codice per eseguire i controlli.

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

Ecco come utilizzare gli asserti in:

risposta data 11.08.2011 - 08:04
fonte
2

Come tutto il resto dipende ....

Se i metodi pubblici sono semplici wrapper che chiamano il metodo privato (sulla falsariga di un metodo privato sovraccarico), allora potrebbe avere senso lanciare un'eccezione nel metodo privato invece di registrarne uno pubblico.

Generalmente se non soddisfa la definizione di cui sopra allora di solito non controllerei gli argomenti / lanciare un'eccezione su un metodo privato. Sebbene ci siano altri casi, generalmente lo faccio in un metodo privato prima di eseguire alcune costose operazioni che potrebbero fallire in parte se gli argomenti non sono validi.

    
risposta data 11.08.2011 - 17:17
fonte
1

Considera la seguente struttura:

  1. Logica interna: questa funzione si presume essere chiamata con parametri corretti e quindi usa asserzioni per verificare precondizioni, postcondizioni e invarianti per verificare la logica interna.

  2. Wrapper dell'interfaccia utente: questa funzione avvolge la funzione interna e utilizza InvalidArgumentExceptions per gestire valori errati e per dire all'utente di correggere i suoi input: Assert(x).hasLength(4); , Assume(y).isAlphanumeric(); , Assert(z).isZipCode(); , Assume(mailAdress).matchesRegex(regex_MailAdress); , Reject(x).ifEmpty(); , ecc.

  3. wrapper dell'interfaccia batch: questa funzione avvolge 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 interfaccia riga di comando: questa funzione avvolge la funzione interna e chiede di nuovo l'ultimo input.

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

    
risposta data 17.07.2013 - 17:22
fonte
1

Mi rendo conto che mentre la domanda non ha tag di linguaggio, probabilmente sta parlando implicitamente di "lingue del caffè". Ma solo per completezza, vorrei menzionare il consenso apparente un po 'divergente nel mondo C ++.

Ci sono tre cose in cui i programmatori C ++ saranno in genere interessati:

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

In passato, ho affrontato il primo problema scrivendo un 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 è #define d a una costante in fase di compilazione, in modo che il compilatore possa eliminare completamente tutto il codice di verifica degli argomenti nelle build ottimizzate. (Non sto dicendo che compilare i check out sia una cosa buona in generale, ma credo che un utente dovrebbe avere l'opzione per compilarli.)

Mi piace ancora di questa soluzione che il codice di controllo degli argomenti sia chiaramente visibile raggruppato in if . Tuttavia, il secondo e il terzo problema non sono risolti da questo. Pertanto, ora mi sto appoggiando di più verso l'utilizzo di una macro assert per il controllo degli argomenti.

Gli standard di codifica potenziati sono d'accordo con questo:

What About Programmer Errors?

As a developer, if I have violated a precondition of a library I'm using, I don't want stack unwinding. What I want is a core dump or the equivalent - a way to inspect the state of the program at the exact point where the problem was detected. That usually means assert() or something like it.

C'è stata una conversazione molto interessante tenuta da John Lakos in CppCon'14 intitolata Programmazione difensiva eseguita a destra ( parte 1 , parte 2 ). Nella prima parte del suo discorso, discute la teoria dei contratti e il comportamento indefinito. Nella seconda parte, presenta ciò che considero un'ottima proposta per il controllo sistematico degli argomenti. In sostanza, propone macro di asserzione che consentono all'utente di selezionare la quantità di budget (in termini di utilizzo della CPU) che è disposta a donare alla libreria per il controllo degli argomenti e fa in modo che la biblioteca faccia un uso saggio di tale budget. Come aggiunta, l'utente può anche installare una funzione di gestione degli errori globale che verrà chiamata nel caso in cui venga rilevato un contratto interrotto.

Riguardo all'aspetto che una funzione è privata, non penso che questo significhi che mai debba controllarne gli argomenti. Potremmo fidarci più 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, quanto nelle funzioni pubbliche per il rilevamento di errori nel codice client.

    
risposta data 01.10.2015 - 02:32
fonte
0

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

    
risposta data 11.08.2011 - 07:54
fonte

Leggi altre domande sui tag