Іноді мені доводиться писати метод або властивість для бібліотеки класів, на яку не є винятковою не справжня відповідь, а невдача. Щось неможливо визначити, недоступне, не знайдене, наразі неможливо або більше даних немає.
Я думаю, що для такої порівняно невиключної ситуації є три можливі рішення, що свідчать про збій у 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існували.