sta generando un'eccezione da una cattiva proprietà?

13

Ho sempre pensato che le proprietà (cioè le loro operazioni set / get) dovessero essere veloci / immediate e prive di errori. Non dovresti mai provare a capire come ottenere o impostare una proprietà.

Ma sto osservando alcuni modi per applicare la sicurezza basata sui ruoli sulle proprietà di alcuni oggetti. Ad esempio una proprietà Employee.Salary. Alcune delle soluzioni che ho incontrato sono state provate da altre (una in particolare è l'esempio AOP qui ) implicano il lancio di un'eccezione se l'accessor non ha i permessi giusti - ma questo va contro una regola personale che ho avuto per molto tempo.

Quindi chiedo: ho sbagliato? Sono cambiate le cose? È stato accettato che le proprietà dovrebbero essere in grado di generare eccezioni?

    
posta Steven Evers 04.11.2010 - 00:52
fonte

7 risposte

14

quando imposti il valore di una proprietà, il lancio di un'eccezione su un valore non valido va bene

ottenere il valore di una proprietà dovrebbe (quasi) non generare mai un'eccezione

per l'accesso basato sui ruoli, utilizzare interfacce / facciate diverse / più scomode; non lasciare che le persone vedano cose che non possono avere!

    
risposta data 04.11.2010 - 01:52
fonte
5

Lo considero in gran parte una cattiva forma, ma anche Microsoft consiglia di utilizzare le eccezioni a volte. Un buon esempio è la proprietà astratta Stream.Length . Come linee guida, sarei più interessato a evitare gli effetti collaterali sui getter e limitare gli effetti collaterali sui setter.

    
risposta data 04.11.2010 - 01:24
fonte
3

Sosterrei sicuramente che c'è un difetto nel design se senti la necessità di lanciare eccezioni da un setter o da un getter di proprietà.

Una proprietà è un'astrazione che rappresenta qualcosa che è solo un valore . E dovresti essere in grado di impostare un valore senza temere che farlo potrebbe generare un'eccezione. *

Se l'impostazione della proprietà produce un effetto collaterale, ciò dovrebbe invece essere implementato come metodo. E se non produce effetti collaterali, non deve essere lanciata alcuna eccezione.

Un esempio già menzionato in una risposta diversa è Stream.Position proprietà. Ciò produce effetti collaterali e può generare eccezioni. Ma questo setter di proprietà è fondamentalmente solo un involucro attorno a Stream.Seek che potresti chiamare invece.

Personalmente, credo che la posizione non avrebbe dovuto essere una proprietà scrivibile.

Un altro esempio in cui potresti essere tentato di lanciare un'eccezione da un setter di proprietà è la convalida dei dati:

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

Ma c'è una soluzione migliore a questo problema. Introduci un tipo che rappresenta un indirizzo email valido:

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

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

La classe Email garantisce che non possa contenere un valore che non è un indirizzo email valido e le classi che devono memorizzare le e-mail sono sollevate dal dovere di convalidarle.

Ciò porta anche a una maggiore coesione (un indicatore di buona progettazione del software): la conoscenza di cosa sia un indirizzo di posta elettronica e di come viene convalidato esiste solo nella classe Email , che ha solo questo problema.

* ObjectDisposedException è l'unica eccezione valida (nessun gioco di parole) a cui riesco a pensare al momento.

    
risposta data 07.01.2015 - 15:50
fonte
2

So che la tua domanda è specifica per .NET , ma dal momento che C # condivide un po 'di storia con Java, ho pensato che potresti essere interessato. Sono not in qualsiasi modo implicando che, poiché qualcosa è fatto in Java, dovrebbe essere fatto in C #. So che i due sono molto diversi, specialmente nel modo in cui C # ha un supporto linguistico molto migliorato per le proprietà. Sto solo dando un po 'di contesto e prospettiva.

Dalla specifica JavaBeans :

Constrained properties Sometimes when a property change occurs some other bean may wish to validate the change and reject it if it is inappropriate. We refer to properties that undergo this kind of checking as constrained properties. In Java Beans, constrained property setter methods are required to support the PropertyVetoException. This documents to the users of the constrained property that attempted updates may be vetoed. So a simple constrained property might look like:

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

Prendi tutto questo con un pizzico di sale, per favore. La specifica JavaBeans è vecchia e C # Properties è (IMO) un enorme miglioramento rispetto alle proprietà basate sulla "naming convention" di Java. Sto solo provando a dare un piccolo contesto, è tutto!

    
risposta data 04.11.2010 - 01:42
fonte
2

Il punto di una proprietà è il principio di accesso uniforme , vale a dire che un valore dovrebbe essere accessibile attraverso la stessa interfaccia sia implementato da storage o computazione. Se la tua proprietà sta generando un'eccezione che rappresenta una condizione di errore oltre il controllo del programmatore, il tipo che si suppone venga catturato e gestito, stai costringendo il tuo client a sapere che il valore è ottenuto tramite il calcolo.

D'altra parte, non vedo alcun problema con l'utilizzo di asserzioni o eccezioni simili ad asserzioni che hanno lo scopo di segnalare un uso errato dell'API al programmatore piuttosto che essere scoperti e gestiti. In questi casi, la risposta corretta dal punto di vista dell'utente dell'API non è quella di gestire l'eccezione (così implicitamente si preoccupa se il valore è ottenuto tramite calcolo o memorizzazione). È per correggere il suo codice in modo che l'oggetto non finisca in uno stato non valido o ti prepari a correggere il codice in modo che l'asserzione non venga attivata.

    
risposta data 04.11.2010 - 01:41
fonte
1

AFAIK, questa guida deriva principalmente dal processo di pensiero che le proprietà possono essere utilizzate al tempo design . (Ad esempio, la proprietà Text su un TextBox) Se la proprietà lancia un'eccezione quando un designer sta tentando di accedervi, VS non avrà una buona giornata. Otterrete un sacco di errori solo cercando di utilizzare il designer e per i progettisti dell'interfaccia utente, che non renderanno. Si applica anche al tempo di debug, anche se quello che vedrai in uno scenario di eccezione è solo "xxx Exception" e non rovinerà VS IIRC.

Per i POCO, non farà davvero alcun danno, ma io ancora evito di farlo da solo. Immagino che le persone vorranno accedere alle proprietà più frequentemente, quindi dovrebbero essere normalmente a basso costo. Le proprietà non dovrebbero fare il lavoro dei metodi, dovrebbero solo ottenere / impostare alcune informazioni e farle come regola generale.

    
risposta data 04.11.2010 - 01:35
fonte
0

Anche se molto dipenderà dal contesto, in generale eviterò di inserire qualsiasi tipo di logica frazionabile (comprese le eccezioni) nelle proprietà. Proprio come un esempio, ci sono un sacco di cose che tu (o qualche libreria che stai usando) potresti fare, che usano la riflessione per scorrere le proprietà con conseguenti errori che non avevi previsto in fase di progettazione.

Dico generalmente anche se ci possono essere delle volte in cui assolutamente, assolutamente, vuoi bloccare qualcosa senza preoccuparti troppo delle conseguenze. Sicurezza credo che sarebbe il caso classico lì.

    
risposta data 04.11.2010 - 14:04
fonte

Leggi altre domande sui tag