我有一个包含许多字段的类,它们代表不同的物理值。
class Tunnel
{
private double _length;
private double _crossSectionArea;
private double _airDensity;
//...
使用读/写属性公开每个字段。我需要检查setter的值是否正确,否则生成异常。所有验证都是类似的:
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;
}
}
//...
有没有优雅而灵活的方法来完成此类验证?
答案 0 :(得分:6)
假设您想要这种行为,您可以考虑一些辅助方法,例如
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;
}
然后你可以写:
public double AirDensity
{
get { return _airDensity; }
set
{
_airDensity = ValidationHelpers.ValidateNonNegative(value,
"Air density");
}
}
如果你需要各种类型,你甚至可以使它通用:
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;
}
请注意,这些都不是非常友好的......
答案 1 :(得分:3)
一切都取决于您使用的技术 - 如果您使用的是MVC,您可以使用属性,就像这样;
http://msdn.microsoft.com/en-us/library/ee256141(v=vs.98).aspx
答案 2 :(得分:3)
这是我的版本,它在某些方面比Jon的版本更清晰:
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;
}
答案 3 :(得分:1)
尝试使用这样的方法:
public void FailOrProceed(Func<bool> validationFunction, Action proceedFunction, string errorMessage)
{
// !!! check for nulls, etc
if (!validationFunction())
{
throw new ArgumentOutOfRangeException(errorMessage);
}
proceedFunction();
}
答案 4 :(得分:1)
您可以使用System.ComponentModel.DataAnnotations
class Tunnel
{
[Range(0, double.MaxValue, ErrorMessage = "Length must be positive value.")]
public double Length { get; set; }
}
验证:
var tunnel = new Tunnel { Length = 0 };
var context = new ValidationContext(tunnel, null, null);
Validator.ValidateObject(tunnel, context, true);
您还可以实现自己的验证属性,覆盖ValidationAttribute
类
答案 5 :(得分:1)
答案 6 :(得分:1)
使用我在上面的评论中提到的Validator函数,我会做这样的事情(未经测试的代码):
void textBox_Changed(object sender, EventArgs e) {
submitButton.Enabled = validator();
}
bool validator() {
const string NON_POSITIVE = "Value must be greater than Zero";
bool result = false;
string controlName = "Length";
try {
_length = Convert.ToDouble(txtLength.Text);
if (_length <= 0) throw new Exception(NON_POSITIVE);
controlName = "Cross Section Area";
_crossSectionArea = Convert.ToDouble(txtCrossSectionArea.Text);
if (_crossSectionArea <= 0) throw new Exception(NON_POSITIVE);
controlName = "Air Density";
_airDensity = Convert.ToDouble(txtAirDensity.Text);
if (_airDensity <= 0) throw new Exception(NON_POSITIVE);
result = true; // only do this step last
} catch (Exception err) {
MessageBox.Show(controlName + " Error: " + err.Message, "Input Error");
}
return result;
}
John Skeet可能有更好的方法,但这很有效。 :)