2

In C# I'm writing a class that checks the values of its properties with a setter method:

private int _grade
public int Grade {
    get { return _grade;}
    set { if (value >= this.lowerLimit) _grade = value; }
}

I would like to signal to the application if a value was rejected. I had considered refactoring to use a setGrade function that returns a bool (accepted / rejected) but the ability to do someInstance.Grade++ and someInstance.Grade*=2 are important. Simple functions incrementGrade and divideGrade will make the code a mess, and there will certainly be some function that I forgot to implement (too much coupling).

My current solution is to check the value of someInstance.Grade after setting it, to ensure that it has been set. But it seems to me that this is just moving the mess from the class to the application. Indeed, it is the responsibility of the application to ensure that the value was properly set.

How do those more experienced handle this? Thanks!

dotancohen
  • 30,064
  • 36
  • 138
  • 197
  • Usually an exception is thrown ([ArgumentOutOfRangeException](http://msdn.microsoft.com/en-us/library/system.argumentoutofrangeexception.aspx)) – Christopher Currens Aug 09 '11 at 22:25

3 Answers3

7

It is indeed caller's responsibility to set values that make sense.
Normally, it is accepted practice to throw ArgumentOutOfRangeException in the setter when the value is wrong. If the caller expects possibly wrong value (e.g. user input), it can catch the right exception.

private int _grade
public int Grade {
    get { return _grade;}
    set {
        if (value < lowerLimit) {
            throw new ArgumentOutOfRangeException("value",
                string.Format("Grade must be higher than or equal to {0}.", lowerLimit)
            );
        }

        _grade = value; // will not happen if the exception was thrown
    }
}

There is also ArgumentNullException for null values when you don't want them, and general ArgumentException if your argument rejection reason is different from these two cases.

A more hip approach would be to use Code Contracts as suggested by Jean-Bernard.
However this feature is still somewhat new and not widely used in .NET projects.

Code Contracts add static analysis so you discover such errors at compilation stage.
They will still throw ArgumentExceptions in runtime, though.

Community
  • 1
  • 1
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • Thanks, exceptions seem to be exactly made for this purpose. The fact that there exists ArgumentOutOfRangeException proves that. Thank you! – dotancohen Aug 09 '11 at 22:55
2

You could use Code Contracts
Here is an answer to another question which has more resources: link

Community
  • 1
  • 1
Jean-Bernard Pellerin
  • 12,556
  • 10
  • 57
  • 79
1

Most of the time, I either silently adjust the value given to be within the range of values, or throw an Exception, depending on the situation.

Another option: you could make an event PropertyValueRejected that your class's clients could subscribe to:

public class PropertyValueRejectedEventArgs {
    public string PropertyName { get; set; }
    public object RejectedValue { get; set; }
}

public class MyClass {

    public event EventHandler<PropertyValueRejectedEventArgs> PropertyRejected;

    private int _grade = -1;
    public int Grade {
        get { return _grade; }
        set {

            if (value >= this.lowerLimit) {
                _grade = value;
            } 
            else if (PropertyRejected != null) {     
                PropertyRejected(
                    this, 
                    new PropertyValueRejectedEventArgs {
                        PropertyName = "Grade",
                        RejectedValue = value
                    }
                ); 
            }                
        }
    }
}
FishBasketGordo
  • 22,904
  • 4
  • 58
  • 91
  • Thanks, I will play around with using events. That might work if I find the exceptions to be too cumbersome. – dotancohen Aug 09 '11 at 22:56