Czy zgłoszenie wyjątku od nieruchomości jest złe?

15

Zawsze byłem przekonany, że właściwości (tj. Ich operacje ustawiania / pobierania) powinny być szybkie / natychmiastowe i bezawaryjne. Nigdy nie powinieneś próbować / łapać się za uzyskanie lub ustawienie nieruchomości.

Ale patrzę na niektóre sposoby zastosowania zabezpieczeń opartych na rolach do właściwości niektórych obiektów. Na przykład właściwość Employee.Salary. Niektóre rozwiązania, na które natknąłem się, które wypróbowały inne (jednym z nich jest tutaj przykład AOP ), polegające na zgłoszeniu wyjątku, jeśli akcesorium nie ma odpowiednich uprawnień - ale jest to sprzeczne z osobistą regułą, którą miałem od dłuższego czasu.

Więc pytam: czy się mylę? Czy coś się zmieniło? Czy przyjęto, że nieruchomości powinny mieć możliwość zgłaszania wyjątków?

Steven Evers
źródło
1
To samo pytanie na StackOverflow zyskało większą uwagę i dzięki temu lepsze odpowiedzi.
Roman Starkov,

Odpowiedzi:

14

gdy ustawisz wartość właściwości, rzucanie wyjątku na niepoprawną wartość jest w porządku

uzyskanie wartości właściwości nie powinno (prawie) nigdy wyrzucać wyjątku

dla dostępu opartego na rolach użyj różnych / głupszych interfejsów lub fasad; nie pozwól ludziom zobaczyć rzeczy, których nie mogą mieć!

Steven A. Lowe
źródło
5

Uważam, że jest to w większości zła forma, ale nawet Microsoft zaleca czasem stosowanie wyjątków. Dobrym przykładem jest abstrakcyjna właściwość Stream.Length . Zgodnie z wytycznymi bardziej będę zainteresowany unikaniem skutków ubocznych u osób pobierających i ograniczaniem skutków ubocznych u osób ustawiających.

ChaosPandion
źródło
4

Zdecydowanie twierdzę, że projekt ma wadę, jeśli odczuwasz potrzebę rzucenia wyjątków od ustawiacza nieruchomości lub gettera.

Właściwość jest abstrakcją, która reprezentuje coś, co jest tylko wartością . Powinieneś być w stanie ustawić wartość bez obawy, że może to spowodować wyjątek. *

Jeśli ustawienie właściwości powoduje efekt uboczny, należy ją zaimplementować jako metodę. A jeśli nie wywołuje to żadnych skutków ubocznych, nie należy rzucać żadnych wyjątków.

Jednym z przykładów wspomnianych już w innej odpowiedzi jest Stream.Positionwłaściwość. To powoduje skutki uboczne i może rzucać wyjątki. Ale to narzędzie do ustawiania właściwości jest po prostu opakowaniem Stream.Seek, które można zamiast tego wywołać.

Osobiście uważam, że to stanowisko nie powinno być własnością do zapisu.

Innym przykładem, w którym możesz ulec pokusie rzucenia wyjątku z ustawiacza właściwości, jest sprawdzanie poprawności danych:

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

Ale istnieje lepsze rozwiązanie tego problemu. Wprowadź typ reprezentujący prawidłowy adres e-mail:

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

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

Do Emailklasy zapewnia, że nie może posiadać wartość, która nie jest prawidłowy adres e-mail i klas, które trzeba przechowywać e-maile są zwolnione z obowiązku ich zatwierdzania.

Prowadzi to również do większej spójności (wskaźnik dobrego projektu oprogramowania) - wiedza o tym, czym jest adres e-mail i jak jest weryfikowany, istnieje tylko w Emailklasie, która ma tylko takie obawy.

* ObjectDisposedException to jedyny prawidłowy wyjątek (bez zamierzonej gry słów), o którym mogę teraz myśleć.

Pete
źródło
2

Wiem, że twoje pytanie jest specyficzne dla .NET , ale ponieważ C # udostępnia trochę historii z Javą, pomyślałem, że możesz być zainteresowany. Jestem nie w żaden sposób sugerując, że skoro coś jest zrobione w Javie, należy to zrobić w języku C #. Wiem, że oba są bardzo różne, zwłaszcza w tym, że C # ma znacznie ulepszoną obsługę właściwości na poziomie języka. Podaję tylko kontekst i perspektywę.

Ze specyfikacji JavaBeans :

Ograniczone właściwości Czasami, gdy nastąpi zmiana właściwości, inna fasola może chcieć zatwierdzić zmianę i odrzucić ją, jeśli jest nieodpowiednia. Właściwości, które podlegają tego rodzaju kontroli, nazywamy właściwościami ograniczonymi. W komponentach Java Beans wymagane są ograniczone metody ustawiania właściwości do obsługi wyjątku PropertyVetoException. Dokumentuje to użytkownikom ograniczonej właściwości, że próby aktualizacji mogą zostać zawetowane. Prosta ograniczona właściwość może więc wyglądać następująco:

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

Proszę, weź to wszystko z odrobiną soli. Specyfikacja JavaBeans jest stara, a właściwości C # są (IMO) ogromną poprawą w stosunku do właściwości opartych na „konwencji nazewnictwa”, które ma Java. Próbuję tylko dać trochę kontekstu, to wszystko!

Mike Clark
źródło
To dobra uwaga, ale rozróżnienie między metodą ustawiającą a ustawiaczem właściwości ac # jest na tyle znaczące, że może być dla mnie innym przypadkiem. Podobnie, sprawdzone wyjątki Javy zmuszają kod wywołujący do świadomości, że wyjątek może zostać zgłoszony, więc istnieje mniejsze prawdopodobieństwo, że zaskoczy on każdego.
Steven Evers,
2

Punktem właściwości jest zasada jednolitego dostępu , tzn. Że wartość powinna być dostępna za pośrednictwem tego samego interfejsu, niezależnie od tego, czy jest implementowana przez pamięć, czy obliczenia. Jeśli twoja właściwość zgłasza wyjątek, który reprezentuje warunek błędu, na który programista nie ma wpływu, rodzaj, który powinien zostać przechwycony i obsłużony, zmuszasz swojego klienta do zrozumienia, że ​​wartość jest uzyskiwana przez obliczenia.

Z drugiej strony nie widzę żadnego problemu z używaniem asercji lub wyjątków podobnych do asercji, które mają na celu zasygnalizowanie programatorowi niewłaściwego użycia API, a nie bycia złapanym i obsługiwanym. W takich przypadkach poprawna odpowiedź z perspektywy użytkownika interfejsu API nie obsługuje wyjątku (tym samym domyślnie dba o to, czy wartość jest uzyskiwana poprzez obliczenia, czy przechowywanie). Ma to na celu naprawienie jego / jej kodu, aby obiekt nie kończył się niepoprawnym stanem lub zmusił go do poprawienia kodu, aby asercja nie została uruchomiona.

dsimcha
źródło
Nie rozumiem, w jaki sposób „zmuszasz swojego klienta do zrozumienia, że ​​wartość jest uzyskiwana przez obliczenia”. Z pewnością dostęp do pamięci masowej może również rzucić wyjątek. Jak w ogóle zdefiniowałbyś różnicę między nimi?
Timwi
Uważam, że rozróżnia się to, że po prostu odzyskanie wartości z pola (przechowywanie) i zrobienie z nią czegoś nieszkodliwego, na przykład umieszczenie jej w zmiennej odpowiedniego typu (tj. Bez rzutowania), nie może wyrzucić wyjątku. W takim przypadku wyjątek może wystąpić tylko wtedy, gdy zrobisz coś z wartością. Jeśli wyjątek jest zgłaszany w module pobierania właściwości, wówczas w takim przypadku po prostu pobranie wartości i umieszczenie jej w zmiennej może spowodować wyjątek.
Dr Wily's Apprentice
1

AFAIK, niniejsze wskazówki pochodzą przede wszystkim z procesu myślowego, w którym właściwości mogą ostatecznie zostać wykorzystane czasie projektowania . (Np. Właściwość Text w TextBox) Jeśli właściwość rzuca wyjątek, gdy projektant próbuje uzyskać do niej dostęp, VS nie będzie miał dobrego dnia. Podczas próby użycia projektanta pojawi się mnóstwo błędów, a dla projektantów interfejsu użytkownika nie będą renderowane. Dotyczy to również czasu debugowania, chociaż w scenariuszu wyjątku zobaczysz tylko „wyjątek xxx” i nie będzie on blokował VS IIRC.

W przypadku POCO tak naprawdę nie wyrządzi to żadnej szkody, ale wciąż unikam robienia tego sam. Myślę, że ludzie będą chcieli częściej uzyskiwać dostęp do nieruchomości, więc zwykle powinny być tanie. Właściwości nie powinny wykonywać pracy metod, powinny po prostu uzyskać / ustawić pewne informacje i powinny być z tym zrobione jako ogólna zasada.

MIA
źródło
0

Chociaż wiele będzie zależeć od kontekstu generalnie unikałbym umieszczania jakiejkolwiek łamliwej logiki (w tym wyjątków) we właściwościach. Przykładowo, istnieje wiele rzeczy, które możesz zrobić (lub niektóre biblioteki, których używasz), które wykorzystują refleksję do iteracji właściwości, powodując błędy, których nie spodziewałeś się w czasie projektowania.

Mówię ogólnie, ponieważ mogą zdarzyć się chwile, kiedy absolutnie, zdecydowanie chcesz coś zablokować, nie martwiąc się zbytnio o konsekwencje. Bezpieczeństwo to chyba klasyczna sprawa.

FinnNk
źródło