A volte finisco per dover scrivere un metodo o una proprietà per una libreria di classi per la quale non è eccezionale avere una risposta reale, ma un fallimento. Qualcosa non può essere determinato, non è disponibile, non è stato trovato, non è attualmente possibile o non ci sono più dati disponibili.
Penso che ci siano tre possibili soluzioni per una situazione relativamente non eccezionale per indicare un errore in C # 4:
- restituisce un valore magico che non ha altro significato (come
null
e-1
); - genera un'eccezione (ad esempio
KeyNotFoundException
); - restituisce
false
e fornisce il valore di ritorno effettivo in un parametroout
, (ad esempioDictionary<,>.TryGetValue
).
Quindi le domande sono: in quale situazione non eccezionale dovrei lanciare un'eccezione? E se non dovessi lanciare: quando restituisce un valore magico perferito sopra implementando un Try*
metodo con un parametro out
? (Per me il parametro out
sembra sporco, ed è più difficile utilizzarlo correttamente.)
Sto cercando risposte concrete, come le risposte che riguardano le linee guida di progettazione (non ne conosco i metodi Try*
), l'usabilità (come chiedo questo per una libreria di classi), l'uniformità con il BCL e la leggibilità .
Nella libreria di classi base di .NET Framework, vengono utilizzati tutti e tre i metodi:
- restituisce un valore magico che non ha altro significato:
-
Collection<T>.IndexOf
restituisce -1, -
StreamReader.Read
restituisce -1, -
Math.Sqrt
restituisce NaN, -
Hashtable.Item
restituisce null;
-
- genera un'eccezione:
-
Dictionary<,>.Item
genera KeyNotFoundException, -
Double.Parse
genera FormatException; o
-
- return
false
e fornisce il valore di ritorno effettivo in un parametroout
:
Si noti che quando Hashtable
è stato creato nel momento in cui non c'erano generici in C #, utilizza object
e può quindi restituire null
come valore magico. Ma con i generici, le eccezioni sono usate in Dictionary<,>
e inizialmente non aveva TryGetValue
. A quanto pare le intuizioni cambiano.
Ovviamente, il Item
- TryGetValue
e Parse
- TryParse
dualità è lì per un motivo, quindi presumo che lanciare eccezioni per errori non eccezionali sia in C # 4 non fatto . Tuttavia, i metodi Try*
non sono sempre esistiti, anche se esisteva Dictionary<,>.Item
.