Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 验证值的优雅方式_C#_.net_Validation - Fatal编程技术网

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;
}