There's another option, that might be a bit combersome but will ensure the given ranges, is not to use double
at all, but create a custom class called Grade
. Your Grade
class will contain casts from and to double
, and will enforce validation.
This means that all Grade validation logic is in the Grade
struct, and the Student
class just receives a Grade
object and doesn't have to worry about it.
public struct Grade
{
public static readonly double MinValue = 2.0;
public static readonly double MaxValue = 6.0;
private double value;
public static explicit operator double(Grade grade)
{
return grade.value + MinValue;
}
public static explicit operator Grade(double gradeValue)
{
if (gradeValue < MinValue || gradeValue > MaxValue)
throw new ArgumentOutOfRangeException("gradeValue", "Grade must be between 2.0 and 6.0");
return new Grade{ value = gradeValue - MinValue };
}
}
And you would use it like this:
double userInput = GetUserInputForGrade();
Grade grade = (Grade)userInput; // perform explicit cast.
Student student = new Student(firstName, lastName, grade);
Edit: I've updated the code with @EricLippert's suggestions, to make the class expose its min/max values to a developer.
Edit 2: Updated again with @JeppeStigNielsen's suggestion. The value
field now stores an offset from MinValue, so that a call to default(Grade)
will return a valid value (equal to MinValue) regardless of whether 0 is inside the valid range.