C# 验证值的优雅方式
我有一个包含许多字段的类,这些字段表示不同的物理值C# 验证值的优雅方式,c#,.net,validation,C#,.net,Validation,我有一个包含许多字段的类,这些字段表示不同的物理值 class Tunnel { private double _length; private double _crossSectionArea; private double _airDensity; //... 每个字段都使用读/写属性公开。我需要检查setter的值是否正确,否则生成异常。所有验证都是相似的: public double Length { get { retu
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;
}
}
//...
公共双倍长度
{
获取{return_length;}
设置
{
if(value完全取决于您使用的技术-如果您使用的是MVC,则可以使用属性,如下所示
假设你想要这种行为,你可以考虑一些帮助方法,例如
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 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;
}
public static T ValidateNonNegative(T输入,字符串名称)
其中T:i可比较
{
if(input.CompareTo(默认值(T))<0)
{
抛出新ArgumentOutOfRangeException(名称+“不能为负”);
}
返回输入;
}
请注意,所有这些都不是非常友好的…尝试使用以下方法:
public void FailOrProceed(Func<bool> validationFunction, Action proceedFunction, string errorMessage)
{
// !!! check for nulls, etc
if (!validationFunction())
{
throw new ArgumentOutOfRangeException(errorMessage);
}
proceedFunction();
}
public void FailOrProceed(Func validationFunction、Action proceedFunction、string errorMessage)
{
//!!!检查空值等
如果(!validationFunction())
{
抛出新ArgumentOutOfRangeException(errorMessage);
}
proceedFunction();
}
您可以使用
验证:
var tunnel = new Tunnel { Length = 0 };
var context = new ValidationContext(tunnel, null, null);
Validator.ValidateObject(tunnel, context, true);
您还可以通过创建自己的验证属性来实现自己的验证属性覆盖类是
阅读本文:
我将有礼貌地不在这里复制它。:)
使用我在上面的评论中提到的验证器函数,我会这样做(未经测试的代码):
void textBox\u已更改(对象发送方,事件参数e){
submitButton.Enabled=validator();
}
bool验证器(){
常量字符串非正=“值必须大于零”;
布尔结果=假;
string controlName=“长度”;
试一试{
_长度=Convert.ToDouble(txtLength.Text);
如果(_length这是我的版本,它在某些方面比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;
}
接口IValidator
{
bool验证(T值);
}
类验证程序:IValidator
{
公共bool验证(int值)
{
返回值>10&&value<15;
}
}
类Int2Validator:IValidator
{
公共bool验证(int值)
{
返回值>100&&value<150;
}
}
结构属性,其中P:IValidator,新()
{
公共价值
{
设置
{
if(m_validator.Validate(value))
{
m_值=值;
}
其他的
{
Console.WriteLine(“验证错误:“+value+””超出范围。”);
}
}
获取{返回m_值;}
}
T m_值;
静态IValidator m_验证器=新P();
}
班级计划
{
静态void Main(字符串[]参数)
{
节目
p=新程序();
p、 m_p1.Value=9;
p、 m_p1.值=12;
p、 m_p1.值=25;
p、 m_p2.Value=90;
p、 m_p2.Value=120;
p、 m_p2.Value=250;
}
财产
m_p1;
财产
m_p2;
}
我认为您这样做的方式是正确的。唯一的改变可能是创建一个验证程序函数
,您可以随时调用该函数,一次检查所有值。以我的经验,Visual Studio(不知道您在使用什么)似乎吞并了属性setter中出现的异常。@jp2code,setter中的异常工作正常。刚刚检查。感谢改进代码。但我还不明白“i18n友好”是什么意思…@archer:这些消息是用英文硬编码的。如果你想把它们翻译成另一种语言,你还有更多的工作要做。好的。谢谢你的解释。老鼠!我比我刚才写的小验证程序更喜欢这个。我甚至调用了你的名字!)这似乎肯定会带来一些开销?@Skizz,这是使用属性进行验证,不再是了。我不喜欢在set
accessor中实现验证。我得到的是属性和属性之间的运行时连接。也许.net在这里做了一些聪明的事情。@Skizz,这取决于任务,但很多.NET框架(如实体框架、WPF、ASP.NET MVC等)使用反射。此验证类似于简单的AOP版本。I也不是。MVC属性同时处理客户端和服务器端验证(请参阅Model.IsValid方法)
var tunnel = new Tunnel { Length = 0 };
var context = new ValidationContext(tunnel, null, null);
Validator.ValidateObject(tunnel, context, true);
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;
}
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;
}