Я чув, що рекомендується перевірити аргументи публічних методів:
- Чи слід перевіряти на null, якщо він не очікує нуля?
- Чи повинен метод перевірити його параметри?
- MSDN - CA1062: Валідація аргументів публічних методів (у мене є .NET фон, але питання не є специфічним для C #)
Мотивація зрозуміла. Якщо модуль буде використаний неправильно, ми хочемо негайно кинути виняток замість будь-якої непередбачуваної поведінки.
Що мене турбує, це те, що помилкові аргументи - не єдина помилка, яку можна допустити під час використання модуля. Ось деякі сценарії помилок, коли нам потрібно додати логіку перевірки, якщо ми дотримуємось рекомендацій і не хочемо нарощування помилок:
- Вхідний дзвінок - несподівані аргументи
- Вхідний дзвінок - модуль знаходиться в неправильному стані
- Зовнішній дзвінок - повернуті несподівані результати
- Зовнішній виклик - несподівані побічні ефекти (подвійний вхід у модуль виклику, порушення інших станів залежності)
Я намагався врахувати всі ці умови і написати один простий модуль одним методом (вибачте, не-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;
}
}
Тепер це безпечно =)
Це досить моторошно. Але уявіть, як моторошно це може бути у реальному модулі з десятками методів, складним станом та безліччю зовнішніх викликів (привіт, любителі ін'єкційних залежностей!). Зауважте, що якщо ви викликаєте модуль, поведінка якого може бути замінено (незапечатаний клас у C #), то ви здійснюєте зовнішній виклик, і наслідки не передбачувані для сфери виклику.
Підводячи підсумки, який правильний шлях і чому? Якщо ви можете вибрати один із наведених нижче варіантів, будь ласка, відповідайте на додаткові запитання.
Перевірте використання всього модуля. Чи потрібні одиничні тести? Чи є приклади такого коду? Чи слід обмежувати введення залежності (оскільки це спричинить більше логіки перевірки)? Чи не зручно переміщувати ці чеки на час налагодження (не включати у випуск)?
Перевірте лише аргументи. З мого досвіду, перевірка аргументів - особливо нульова перевірка - є найменш ефективною, тому що помилка аргументу рідко призводить до складних помилок та ескалацій помилок. Більшу частину часу ви отримаєте NullReferenceException
на наступному рядку. То чому перевірка аргументів настільки особлива?
Не перевіряйте використання модуля. Дуже непопулярна думка, ви можете пояснити чому?