Іноді мені доводиться писати метод або властивість для бібліотеки класів, на яку не є винятковою не справжня відповідь, а невдача. Щось неможливо визначити, недоступне, не знайдене, наразі неможливо або більше даних немає.
Я думаю, що для такої порівняно невиключної ситуації є три можливі рішення, що свідчать про збій у C # 4:
- повернути магічне значення, яке не має сенсу інакше (наприклад,
null
та-1
); - кинути виняток (наприклад
KeyNotFoundException
); - повернути
false
і надати фактичне значення повернення вout
параметрі (наприклад,Dictionary<,>.TryGetValue
).
Тож питання: у якій невиключній ситуації я повинен кинути виняток? І якщо я не повинен кидати: коли повертається магічне значення, яке було зазначено вище, реалізуючи Try*
метод з out
параметром ? (Мені out
параметр здається брудним, і його більше працювати правильно.)
Я шукаю фактичні відповіді, такі як відповіді, що містять керівні принципи проектування (я не знаю жодних про Try*
методи), зручність використання (оскільки я прошу це про бібліотеку класів), узгодженість з BCL та читабельність.
У бібліотеці базових класів .NET Framework використовуються всі три методи:
- повернути магічне значення, яке не має значення інакше:
Collection<T>.IndexOf
повертає -1,StreamReader.Read
повертає -1,Math.Sqrt
повертає NaN,Hashtable.Item
повертає нуль;
- киньте виняток:
Dictionary<,>.Item
кидає KeyNotFoundException,Double.Parse
кидає FormatException; або
- повернути
false
і надати фактичне значення повернення вout
параметрі:
Зауважте, що як Hashtable
створено в часи, коли в C # не було дженериків, воно використовує object
і тому може повернутися null
як магічне значення. Але з дженериками винятки використовуються в Dictionary<,>
, і спочатку цього не було TryGetValue
. Мабуть, розуміння змінюються.
Очевидно, що подвійність Item
- TryGetValue
і Parse
- TryParse
є з якоїсь причини, тому я припускаю, що викидання винятків за надзвичайні невдачі в C # 4 не робиться . Однак Try*
методи не завжди існували, навіть коли вони Dictionary<,>.Item
існували.