.net中的数据注释无法验证为十进制值指定的范围

时间:2014-07-10 20:34:04

标签: c# .net range data-annotations

我正在尝试使用System.ComponentModel.DataAnnotations执行一些数据验证,以验证商品的报价是否在1 $到$ 1,000,000的范围内。我创建了一个名为ItemPrice的类,并使用以下属性对其进行修饰:

 public class ItemPrice
{
    [Required (ErrorMessage = "Name is required")]
    public string Name
    {
        get;
        set;
    }
    [Range(1.00,1000000.00)]
    public decimal Price
    {
        get;
        set;
    }
}

稍后我尝试验证此类的实例,其中ItemPrice.Price设置为0.0。以下代码正确确定是否省略了Name值,但从未检测到已输入小于1的价格。谁能告诉我为什么以下代码无法检测到1到1,000,000范围之外的价格?

private void validateMessage(object message)
    {
        if (message == null)
        {
            throw new ArgumentNullException("message null");
        } 

        var context = new ValidationContext(message, serviceProvider: null, items: null);
        var results = new List<ValidationResult>();

        var isValid = Validator.TryValidateObject(message, context, results);
        var sb = new StringBuilder();
        if (!isValid)
        {
                foreach (var validationResult in results)
                {
                    Trace.WriteLine(validationResult.ErrorMessage);
                    if (sb.Length > 0)
                        sb.Append("\n");
                    sb.Append(validationResult.ErrorMessage);
                }
            Exception innerException = new Exception(sb.ToString());
            throw new ArgumentException("Invalid argument(s) in message", innerException);
        }
    }

1 个答案:

答案 0 :(得分:3)

System.Decimal是CLR丑陋的继子。它不认为它是主要类型,如Int32等。最严重的问题是,CLI spec,CLR需要工作的黄金标准,并没有确定Decimal的内部格式。它留作了一个实现细节。

在编写CLI规范时,Decimal应该是什么样子,存在相当大的争议。我们今天使用的是在.NET出现之前很久就定义的那个。但IEEE-754 standard还有相当大的背景噪音,它们也想要标准化的十进制格式。一个标准遭遇任何人试图设定标准的经典问题,它只是添加了另一个。 15年后,每个人仍然会忽视这一点。包括芯片制造商在内,他们需要先让每个人都有充分的理由采用标准的N + 1。

这不行,您无法在流沙上创建标准CLI。所以CLR 支持采用Decimal参数的属性构造函数。它们的值被编码到元数据中,并且元数据的二进制标准是超级重要的超级重要。

解决方法很简单。使用整数类型,十进制值乘以100以获得合理的货币价值。如果您确实需要使用System.Double,则必须获取范围或小数位数。一定要宽容,没有人喜欢在1E-15之前离开并被提醒。您只需在属性构造函数中转换为Decimal。