Чи кидання винятку із властивості погана форма?


15

Мені завжди до душі було те, що властивості (тобто операції їх встановлення / отримання) повинні бути швидкими / негайними та безвідмовними. Вам ніколи не доведеться намагатися / піти навколо отримання або встановлення нерухомості.

Але я дивлюсь на деякі способи застосування рольової безпеки щодо властивостей деяких об’єктів. Наприклад, власність Employee.Salary. Деякі з рішень, які я натрапив на те, що інші спробували (одне, зокрема, приклад AOP тут ), передбачають викидання виключень, якщо у постачальника немає правильних дозволів - але це суперечить особистому правилу, яке я мав вже давно.

Тому я запитую: я помиляюся? Чи змінилися речі? Чи прийнято, що властивості повинні вміти викидати винятки?


1
Це ж запитання на StackOverflow отримало більше уваги і тим кращі відповіді.
Роман Старков

Відповіді:


14

коли ви встановлюєте значення властивості, кидати виняток на недійсне значення - це добре

отримання вартості властивості не повинно (майже) ніколи не кидати виняток

для рольового доступу використовувати різні / більш тупі інтерфейси чи фасади; не дозволяйте людям бачити речі, яких вони не можуть мати!


5

Я вважаю це переважно поганою формою, але навіть Microsoft рекомендує іноді використовувати винятки. Хороший приклад - абстрактна властивість Stream.Length . По мірі вказівок я б більше займався тим, щоб уникати побічних ефектів на геттери і обмежувати побічні ефекти на сетер.


4

Я б напевно стверджував, що в дизайні є недолік, якщо ви відчуваєте необхідність кидати винятки з налаштованого майна або геттера.

Властивість - це абстракція, яка представляє щось, що є лише значенням . І ви повинні мати можливість встановити значення, не побоюючись, що це може призвести до виключення. *

Якщо встановлення властивості призводить до побічного ефекту, це дійсно слід реалізувати замість цього методу. І якщо це не спричинить жодних побічних ефектів, то не слід виключати жодного винятку.

Один з прикладів, що вже згадувався в іншій відповіді, - це Stream.Positionвластивість. Це призводить до побічних ефектів і може спричинити винятки. Але це налаштування властивостей - це лише обгортка, Stream.Seekяку ви можете замість цього зателефонувати.

Особисто я вважаю, що позиція не повинна була бути властивістю для запису.

Інший приклад, коли ви можете спокуситись викинути виняток із налаштування властивості, - це перевірка даних:

public class User {
    public string Email {
        get { return _email; }
        set { 
            if (!IsValidEmail(value)) throw InvalidEmailException(value);
            _email = value;
        }
    }

Але є краще рішення цієї проблеми. Введіть тип, що представляє дійсну адресу електронної пошти:

public class Email {
    public Email(string value) {
        if (!IsValidEmail(value)) throw new InvalidEmailException(value);
        ...
    }
    ...
}

public class User {
    public Email Email { get; set; }
}

У Emailгарантує , що клас не може мати значення, яке не є дійсною адресою електронної пошти, і класи , які потрібно зберігати електронні листи звільняються від обов'язку перевірки їх.

Це також призводить до вищої згуртованості (показник гарного дизайну програмного забезпечення) - знання про те, що таке адреса електронної пошти та як вона перевірена, існує лише у Emailкласі, який стосується лише цієї проблеми.

* ObjectDisposedException - єдиний дійсний виняток (не призначений каламбур), про який я можу подумати на даний момент.


2

Я знаю, що ваше питання стосується .NET , але оскільки C # ділиться деякою історією з Java, я подумав, що вам це може бути цікаво. Я жодним чином не маю на увазі, що оскільки щось робиться на Java, це слід робити на C #. Я знаю, що вони дуже відрізняються, особливо в тому, як C # має значно покращену підтримку властивостей на рівні мови. Я просто даю певний контекст і перспективу.

Із специфікації JavaBeans :

Обмежені властивості Іноді, коли відбувається зміна властивості, якийсь інший боб, можливо, захоче підтвердити зміну та відхилити її, якщо вона невідповідна. Ми називаємо властивості, які проходять цей вид перевірки, як обмежені властивості. У Java Beans потрібні обмежені методи встановлення властивостей для підтримки PropertyVetoException. Ці документи для користувачів обмеженої власності, які намагаються оновити, можуть бути накладені вето. Таким простим обмеженим властивістю може виглядати так:

PropertyType getFoo();
void setFoo(PropertyType value) throws PropertyVetoException;

Прийміть усе це із зерном солі, будь ласка. Специфікація JavaBeans стара, і властивості C # (IMO) - це величезне вдосконалення в порівнянні з властивостями на базі "конвенції іменування". Я просто намагаюся дати трохи контексту, це все!


Це хороший момент, але відмінність між методом сеттера та параметром властивостей ac # є досить вагомим для мене. Крім того, перевірені винятки Java змушують код виклику усвідомлювати, що виняток може бути викинутий, тому менше шансів, що це зловить когось зненацька.
Стівен Еверс

2

Точкою властивості є Принцип єдиного доступу , тобто значення має бути доступним через той самий інтерфейс, незалежно від того, чи реалізовано це для зберігання чи обчислення. Якщо ваша власність кидає виняток, який представляє стан помилки поза контролером програміста, вид, який повинен бути схоплений та оброблений, ви змушуєте свого клієнта знати, що значення отримується за допомогою обчислення.

З іншого боку, я не бачу жодних проблем із використанням тверджень або винятків, що нагадують твердження, які мають на меті сигналізувати про неправильне використання API програмісту, а не для того, щоб їх спіймали та обробляли. У цих випадках правильна відповідь з точки зору користувача API не обробляє виняток (таким чином, неявно піклуючись про те, чи отримано значення за допомогою обчислення чи зберігання). Потрібно виправити його / її код, щоб об'єкт не опинився в недійсному стані або змусив виправити код, щоб твердження не спрацьовувало.


Я не бачу, як «ви змушуєте свого клієнта знати, що значення отримується за допомогою обчислень». Безумовно, доступ до сховища теж може спричинити виняток. Насправді, як би ви навіть визначили різницю між ними?
Тімві

Я вважаю, що відмінність полягає в тому, що просто витягнути значення з поля (сховища) і зробити з ним щось нешкідливе, наприклад, розмістити його в змінній відповідного типу (тобто без кастингу), не може кинути виняток. У такому випадку виняток може статися лише в тому випадку, якщо ви згодом зробили щось із значенням. Якщо виняток закидається в одержувач властивостей, то в такому випадку просто акт отримання значення та розміщення його у змінній може спричинити виняток.
Учень доктора Вілі

1

AFAIK, це керівництво в основному випливає з продуманого процесу, що властивості можуть в кінцевому підсумку використовуватися під час проектування . (Наприклад, властивість Text у TextBox) Якщо властивість кидає виняток, коли дизайнер намагається отримати до нього доступ, VS не матиме гарного дня. Ви отримаєте купу помилок, просто намагаючись використовувати дизайнер, і для дизайнерів інтерфейсу вони не відображатимуться. Він також застосовується до часу налагодження, хоча те, що ви побачите в сценарії винятків, є лише "xxx Винятками", і це не буде халатувати VS IIRC.

Для POCO це дійсно не принесе шкоди, але я все-таки соромлюсь робити це самостійно. Думаю, люди хочуть частіше звертатися до ресурсів, тому вони, як правило, мають низьку вартість. Властивості не повинні виконувати роботу методів, вони повинні просто отримати / встановити певну інформацію та зробити це з нею як загальне правило.


0

Хоча багато що залежатиме від контексту, я взагалі уникаю вкладати у властивості будь-яку порушувану логіку (включаючи винятки). Як один із прикладів, є багато речей, які ви (або якась бібліотека, яку ви використовуєте) могли зробити, що використовує відображення для повторення властивостей, що призводить до помилок, яких ви не передбачили під час проектування.

Я кажу, хоча, як буває, бувають випадки, коли ви абсолютно, безумовно, хочете щось заблокувати, не турбуючись надто про наслідки. Безпека, я думаю, був би класичним випадком.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.