Microsoft guidelines say: "Avoid throwing exceptions from property getters", and I normally follow that.
But my application uses Linq2SQL, and there is the case where my object can be in invalid state because somebody or something wrote nonsense into the database. Consider this toy example:
[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;
}
}
}
Here, I could write code which ensures that my application never writes a Rectangle with a zero-length side into the database. But no matter how bulletproof I make my own code, somebody could open the database with a different application and create an invalid Rectangle, especially one with a 0 for secondSide. (For this example, please forget that it is possible to design the database in a way such that writing a side length of zero into the rectangle table is impossible; my domain model is very complex and there are constraints on model state which cannot be expressed in a relational database).
So, the solution I am gravitating to is to change the getter to:
get
{
if(firstSide > 0 && secondSide > 0) return firstSide/secondSide;
else throw new System.InvalidOperationException("All rectangle sides should have a positive length");
}
The reasoning behind not throwing exceptions from properties is that programmers should be able to use them without having to make precautions about catching and handling them them. But in this case, I think that it is OK to continue to use this property without such precautions:
if the exception is thrown because my application wrote a non-zero rectangle side into the database, then this is a serious bug. It cannot and shouldn't be handled in the application, but there should be code which prevents it. It is good that the exception is visibly thrown, because that way the bug is caught.
if the exception is thrown because a different application changed the data in the database, then handling it is outside of the scope of my application. So I can't do anything about it if I catch it.
Is this a good enough reasoning to get over the "avoid" part of the guideline and throw the exception? Or should I turn it into a method after all? Note that in the real code, the properties which can have an invalid state feel less like the result of a calculation, so they are "natural" properties, not methods.