5

I am aware that for the general case, the answer to "should I throw an exception from a property" is "generally don't, but in some special circumstances it is OK to do so". There is a Microsoft guideline which gives this general answer, and also a question on this site.

Now I am faced with a situation which I think may be one of those "special ones" where it is OK. My question: is this really one of those exceptional situations where throwing the exception is superior to the alternatives? Or is it better to use a getter/setter just like in the general case?

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.

Rumi P.
  • 269

3 Answers3

2

From my point of view this is totally valid. Making sure that valid values are set is important, however if you are still unsure you maybe could move the logic to the constructor of the object (assuming that applies to your environment)

Also check this other post

Is throwing an exception from a property bad form?

Termiux
  • 121
1

You can choose to never let the application build an invalid instance of your object.

private double _firstSide;

[Column(Name="firstSide")]
public double FirstSide {
    get { return this._firstSide; }
    set 
    {
        if(value <= 0) throw new System.InvalidOperationException("All rectangle sides should have a positive length");
        this._firstSide = value;
    }
} 

private double _secondSide;

[Column(Name="secondSide")]
public double SecondSide
{
    get { return this._secondSide; }
    set 
    {
        if(value <= 0) throw new System.InvalidOperationException("All rectangle sides should have a positive length");
        this._secondSide = value;
    }
}

public double SideRatio 
{
    get
    {
        return this.FirstSide / this.SecondSide; // safe
    }
}

Handle the errors when you are building your instance / setting your properties. When it's time to do some algorithms, you can safely access SideRatio without the overhead to handle weird objects.

This way, you have a clear distinction between data access layer which will validate objects, and the use of this objects, which are guaranteed to be safe.

Cyril Gandon
  • 1,346
0

I think what you have in this example is a method not a property. When you code it as a method, you could define a range of valid return values (as the case in many .NET methods such as finding string within another, you get -1 if not found), this way the invoking code could determine the result of the operation rather easily.

If your presented example is just for simplification, then the general case would be to validate data before you create the object - That is partially what constructors are for: Where to put validation in domain models.

Anyway, I guess you can't make your object so gentle in such a way that the caller can use them quite safely without anticipating the possibility of an error. Your doco should advice the user that certain objects are to be created with care.

NoChance
  • 12,532