Ho sentito che si consiglia di convalidare gli argomenti dei metodi pubblici:
- Si dovrebbe verificare la null se non si aspetta null?
- Un metodo dovrebbe convalidare i suoi parametri?
- MSDN - CA1062: Convalida argomenti di metodi pubblici (ho un background .NET ma la domanda non è specifica per C #)
La motivazione è comprensibile. Se un modulo verrà utilizzato in modo errato, vogliamo lanciare immediatamente un'eccezione invece di qualsiasi comportamento imprevedibile.
Ciò che mi preoccupa è che argomenti sbagliati non sono l'unico errore che può essere fatto durante l'uso di un modulo. Ecco alcuni scenari di errore in cui è necessario aggiungere la logica di controllo se seguiamo i consigli e non vogliamo l'escalation degli errori:
- Chiamata in arrivo - argomenti imprevisti
- Chiamata in arrivo: il modulo si trova in uno stato errato
- Chiamata esterna: vengono restituiti risultati imprevisti
- Chiamata esterna - effetti collaterali imprevisti (doppia entrata in un modulo chiamante, interruzione di altri stati di dipendenze)
Ho cercato di prendere in considerazione tutte queste condizioni e scrivere un semplice modulo con un metodo (scusate, ragazzi non C #):
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 =)
È abbastanza inquietante. Ma immagina quanto può essere inquietante in un vero modulo con dozzine di metodi, stato complesso e molte chiamate esterne (ciao, amanti dell'iniezione di dipendenza!). Si noti che se si chiama un modulo il cui comportamento può essere ignorato (classe non sigillata in C #), si sta effettuando una chiamata esterna e le conseguenze non sono prevedibili nell'ambito del chiamante.
Riassumendo, qual è la strada giusta e perché? Se puoi scegliere tra le opzioni di seguito, rispondi ad ulteriori domande, per favore.
Controlla l'utilizzo dell'intero modulo. Abbiamo bisogno di unit test? Esistono esempi di tale codice? L'iniezione di dipendenza dovrebbe essere limitata nell'uso (poiché causerà una maggiore logica di controllo)? Non è pratico spostare quei controlli nel tempo di debug (non includere nella versione)?
Controlla solo gli argomenti. Dalla mia esperienza, il controllo degli argomenti - in particolare il controllo null - è il controllo meno efficace, poiché l'errore degli argomenti raramente porta a errori complessi e escalation di errori. La maggior parte delle volte otterrai una NullReferenceException
riga successiva. Quindi perché i controlli degli argomenti sono così speciali?
Non controllare l'utilizzo del modulo. È un'opinione piuttosto impopolare, puoi spiegare perché?