Sono consapevole che nel caso generale, la risposta a "dovrei lanciare un'eccezione da una proprietà" è "generalmente no, ma in alcune circostanze speciali è OK farlo". Esiste una linea guida Microsoft che fornisce questa risposta generale e anche un domanda su questo sito.
Ora mi trovo di fronte a una situazione che ritengo possa essere una di quelle "speciali" in cui va bene. La mia domanda: questa è davvero una di quelle situazioni eccezionali in cui l'eccezione è superiore alle alternative? O è meglio usare un getter / setter come nel caso generale?
La mia applicazione utilizza Linq2SQL, e c'è il caso in cui il mio oggetto può essere in uno stato non valido perché qualcuno o qualcosa ha scritto assurdità nel database. Considera questo esempio di giocattolo:
[Table(Name="Rectangle")]
public class Rectangle {
[Column(Name="ID", IsPrimaryKey = true, IsDbGenerated = true)]
public int ID {get; set;}
[Column(Name="firstSide")]
public double firstSide {get; set;}
[Column(Name="secondSide")]
public double secondSide {get; set;}
public double sideRatio
{
get
{
return firstSide/secondSide;
}
}
}
Qui, potrei scrivere codice che garantisce che la mia applicazione non scriva mai un rettangolo con un lato di lunghezza zero nel database. Ma non importa quanto sia antiproiettile creare il mio codice, qualcuno potrebbe aprire il database con un'applicazione diversa e creare un rettangolo non valido, specialmente uno con uno 0 per secondSide. (Per questo esempio, si prega di dimenticare che è possibile progettare il database in modo tale che scrivere una lunghezza laterale di zero nella tabella del rettangolo sia impossibile, il mio modello di dominio è molto complesso e ci sono vincoli sullo stato del modello che non possono essere espressi in un database relazionale).
Quindi, la soluzione a cui sto gravitando è di cambiare il getter in:
get
{
if(firstSide > 0 && secondSide > 0) return firstSide/secondSide;
else throw new System.InvalidOperationException("All rectangle sides should have a positive length");
}
Il ragionamento alla base del non fare eccezioni alle proprietà è che i programmatori dovrebbero essere in grado di usarli senza dover prendere precauzioni su come catturarli e gestirli. Ma in questo caso, penso che sia OK continuare ad usare questa proprietà senza tali precauzioni:
- se l'eccezione viene generata perché la mia applicazione ha scritto nel database un rettangolo diverso da zero, questo è un bug grave. Non può e non deve essere gestito nell'applicazione, ma dovrebbe esserci un codice che lo impedisca. È bene che l'eccezione sia visibilmente lanciata, perché in questo modo viene catturato il bug.
- se viene lanciata un'eccezione perché una diversa applicazione modifica i dati nel database, quindi gestirli non rientra nell'ambito della mia applicazione. Quindi non posso farci nulla se lo prendo.
È un ragionamento abbastanza valido per superare la parte "evita" della linea guida e lanciare l'eccezione? O dovrei trasformarlo in un metodo dopotutto? Si noti che nel codice reale, le proprietà che possono avere uno stato non valido si sentono meno come il risultato di un calcolo, quindi sono proprietà "naturali", non metodi.