Elegant way to validate values
Solution 1
Assuming you want this sort of behaviour, you might consider some helper methods, e.g.
public static double ValidatePositive(double input, string name)
{
if (input <= 0)
{
throw new ArgumentOutOfRangeException(name + " must be positive");
}
return input;
}
public static double ValidateNonNegative(double input, string name)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(name + " must not be negative");
}
return input;
}
Then you can write:
public double AirDensity
{
get { return _airDensity; }
set
{
_airDensity = ValidationHelpers.ValidateNonNegative(value,
"Air density");
}
}
If you need this for various types, you could even make it generic:
public static T ValidateNonNegative(T input, string name)
where T : IComparable<T>
{
if (input.CompareTo(default(T)) < 0)
{
throw new ArgumentOutOfRangeException(name + " must not be negative");
}
return input;
}
Note that none of this is terribly i18n-friendly...
Solution 2
All depends what technology you are using - if you're under MVC you can use Attributes, like this;
http://msdn.microsoft.com/en-us/library/ee256141(v=vs.98).aspx
Solution 3
Here's my version, it's a bit cleaner than Jon's version in some respects:
interface IValidator <T>
{
bool Validate (T value);
}
class IntValidator : IValidator <int>
{
public bool Validate (int value)
{
return value > 10 && value < 15;
}
}
class Int2Validator : IValidator<int>
{
public bool Validate (int value)
{
return value > 100 && value < 150;
}
}
struct Property<T, P> where P : IValidator<T>, new ()
{
public T Value
{
set
{
if (m_validator.Validate (value))
{
m_value = value;
}
else
{
Console.WriteLine ("Error validating: '" + value + "' is out of range.");
}
}
get { return m_value; }
}
T m_value;
static IValidator<T> m_validator=new P();
}
class Program
{
static void Main (string [] args)
{
Program
p = new Program ();
p.m_p1.Value = 9;
p.m_p1.Value = 12;
p.m_p1.Value = 25;
p.m_p2.Value = 90;
p.m_p2.Value = 120;
p.m_p2.Value = 250;
}
Property<int, IntValidator>
m_p1;
Property<int, Int2Validator>
m_p2;
}
Solution 4
Try to use such a method:
public void FailOrProceed(Func<bool> validationFunction, Action proceedFunction, string errorMessage)
{
// !!! check for nulls, etc
if (!validationFunction())
{
throw new ArgumentOutOfRangeException(errorMessage);
}
proceedFunction();
}
Solution 5
You can achieve this using classes from System.ComponentModel.DataAnnotations
class Tunnel
{
[Range(0, double.MaxValue, ErrorMessage = "Length must be positive value.")]
public double Length { get; set; }
}
Validation:
var tunnel = new Tunnel { Length = 0 };
var context = new ValidationContext(tunnel, null, null);
Validator.ValidateObject(tunnel, context, true);
Also you can implement your own validation attributes overriding ValidationAttribute
class
kyrylomyr
Updated on July 03, 2022Comments
-
kyrylomyr almost 2 years
I have a class with many fields which represents different physical values.
class Tunnel { private double _length; private double _crossSectionArea; private double _airDensity; //...
Each field is exposed using read/write property. I need to check on setter that the value is correct and generate exception otherwise. All validations are similar:
public double Length { get { return _length; } set { if (value <= 0) throw new ArgumentOutOfRangeException("value", "Length must be positive value."); _length = value; } } public double CrossSectionArea { get { return _crossSectionArea; } set { if (value <= 0) throw new ArgumentOutOfRangeException("value", "Cross-section area must be positive value."); _crossSectionArea = value; } } public double AirDensity { get { return _airDensity; } set { if (value < 0) throw new ArgumentOutOfRangeException("value", "Air density can't be negative value."); _airDensity = value; } } //...
Is there any elegant and flexible way to accomplish such validation?
-
kyrylomyr almost 13 yearsThanks for improving code. But I hasn't understood what you mean about "i18n-friendly"...
-
Jon Skeet almost 13 years@archer: The messages are hard-coded as English. You'll have a bit more work ahead of you if you want to translate them into a different language.
-
kyrylomyr almost 13 yearsOK. Thank you for explanation.
-
jp2code almost 13 yearsRATS! I like this one much better than the little validator routine I just wrote. I even invoked Thy name! :)
-
Skizz almost 13 yearsThis seems like it's going to introduce a bit of overhead surely?
-
Kirill Polishchuk almost 13 years@Skizz, It is validation using attributes, no more. I don't like implement validation inside
set
accessor. -
Skizz almost 13 yearswhat I was getting at was the run time connection between the property and the attribute. Maybe .net does something clever here.
-
Kirill Polishchuk almost 13 years@Skizz, It depends on task, but many .NET frameworks such Entity Framework, WPF, ASP.NET MVC, etc use reflection. This validation is something like simple AOP version.
-
Mikey Hogarth almost 13 yearsNeither was I - the MVC attributes handle both client side and server side validation (see the Model.IsValid method)