Ho sentito che si consiglia di convalidare gli argomenti dei metodi pubblici:
- Se un controllo per null se non si aspetta nulla?
- Un metodo dovrebbe validarne i parametri?
- MSDN - CA1062: convalida degli argomenti dei metodi pubblici (Ho uno sfondo .NET ma la domanda non è C # specifico)
La motivazione è comprensibile. Se un modulo viene utilizzato in modo errato, vogliamo generare un'eccezione immediata anziché un comportamento imprevedibile.
Ciò che mi infastidisce, è che gli argomenti sbagliati non sono l'unico errore che può essere fatto durante l'uso di un modulo. Ecco alcuni scenari di errore in cui dobbiamo aggiungere la logica di controllo se seguiamo i consigli e non vogliamo l'escalation degli errori:
- Chiamata in arrivo - argomenti inattesi
- Chiamata in arrivo - il modulo si trova in uno stato errato
- Chiamata esterna: risultati inattesi restituiti
- Chiamata esterna - effetti collaterali inattesi (doppia entrata in una chiamata modulo, rompendo gli altri stati di dipendenza)
Ho cercato di tenere conto di tutte queste condizioni e di scrivere un modulo semplice con un metodo (mi dispiace, non-C # ragazzi):
public sealed class Room
{
private readonly IDoorFactory _doorFactory;
private bool _entered;
private IDoor _door;
public Room(IDoorFactory doorFactory)
{
if (doorFactory == null)
throw new ArgumentNullException("doorFactory");
_doorFactory = doorFactory;
}
public void Open()
{
if (_door != null)
throw new InvalidOperationException("Room is already opened");
if (_entered)
throw new InvalidOperationException("Double entry is not allowed");
_entered = true;
_door = _doorFactory.Create();
if (_door == null)
throw new IncompatibleDependencyException("doorFactory");
_door.Open();
_entered = false;
}
}
Ora è sicuro =)
È piuttosto inquietante. Ma immagina quanto possa essere raccapricciante in un vero modulo con dozzine di metodi, stato complesso e molte chiamate esterne (ciao, amanti dell'iniezione di dipendenza!). Nota che se stai chiamando un modulo il cui comportamento può essere sovrascritto (classe non sigillata in C #), allora stai facendo una chiamata esterna e le conseguenze non sono prevedibili nell'ambito del chiamante.
Riassumendo, qual è la strada giusta e perché? Se è possibile scegliere tra le opzioni di seguito, rispondere a ulteriori domande, per favore.
Verifica l'intero utilizzo del modulo. Abbiamo bisogno di test unitari? Esistono esempi di tale codice? L'iniezione di dipendenza dovrebbe essere limitata nell'uso (poiché causerà più logica di controllo)? Non è pratico spostare questi controlli in debug-time (non includere nel rilascio)?
Controlla solo argomenti. Dalla mia esperienza, il controllo degli argomenti, in particolare il controllo nullo, è il controllo meno efficace, poiché l'errore degli argomenti raramente causa errori complessi e escalation degli errori. La maggior parte delle volte otterrai un NullReferenceException
alla riga successiva. Allora perché i controlli degli argomenti sono così speciali?
Non controllare l'utilizzo del modulo. È un'opinione impopolare, puoi spiegare perché?