简体   繁体   English

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

[英]Data Annotations in .net fail to validate a range specified for a decimal value

I'm attempting to perform some data validation using System.ComponentModel.DataAnnotations to validate that the offer price for an item falls within a range of 1$ to $1,000,000. 我正在尝试使用System.ComponentModel.DataAnnotations执行一些数据验证,以验证项目的报价是否在1 $到$ 1,000,000的范围内。 I've created a class called ItemPrice and decorated it with the following attributes: 我创建了一个名为ItemPrice的类,并使用以下属性进行装饰:

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

Later I try to validate an instance of this class where ItemPrice.Price is set to 0.0. 后来我尝试验证此类的实例,其中ItemPrice.Price设置为0.0。 The following code correctly determines if the Name value has been omitted, but never detects that a price of less than 1 has been entered. 以下代码正确确定是否省略了Name值,但从未检测到已输入小于1的价格。 Can anyone tell me why the following code would fail to detect a price outside the range of 1 to 1,000,000? 任何人都可以告诉我为什么以下代码无法检测到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);
        }
    }

System.Decimal is the CLR's ugly step-child. System.Decimal是CLR丑陋的继子。 It doesn't consider it a primary type, like Int32 et al. 它不认为它是主要类型,如Int32等。 The most severe problem is that the CLI spec , the Golden Standard for the way the CLR needs to work, does not nail down the internal format of Decimal. 最严重的问题是CLI规范 ,CLR需要工作的黄金标准,并没有确定Decimal的内部格式。 It was left as an implementation detail. 它留作了一个实现细节。

There was considerable debate at the time the CLI spec was written what Decimal should look like. 在编写CLI规范时,Decimal应该是什么样子,这引起了相当大的争议。 The one we use today is one that was defined long before .NET ever came around. 我们今天使用的是在.NET出现之前很久就定义的那个。 But there was considerable background noise from the IEEE-754 standard that also wanted to nail down a standard decimal format. 但是, IEEE-754标准中存在相当大的背景噪声,这些噪声也需要确定标准的十进制格式。 A standard that suffered from the classic problem of anybody trying to set a standard, it just added another one. 一个标准遭遇任何人试图设定标准的经典问题,它只是添加了另一个。 And one that, after 15 years, everybody still ignores. 15年后,每个人仍然会忽视这一点。 Including the chip manufacturers, they need to go first to give everybody a good reason to adopt standard N+1. 包括芯片制造商在内,他们需要首先让每个人都有充分的理由采用标准N + 1。

This will not do, you cannot create a standard CLI on quicksand. 这不行,您无法在流沙上创建标准CLI。 So the CLR does not support attribute constructors that take Decimal arguments. 因此,CLR 支持采取十进制的参数属性的构造函数。 Their values are encoded into the metadata and having a binary standard for metadata is super duper hyper important. 它们的值被编码到元数据中,并且具有元数据的二进制标准是超级重要的超级重要。

The workaround is otherwise simple. 解决方法很简单。 Use an integral type instead, the decimal value multiplied by 100 for reasonable money values. 使用整数类型,十进制值乘以100以获得合理的货币价值。 Use System.Double if you really, really have to to get the range or the fractional digits. 如果您确实需要使用System.Double,则必须获取范围或小数位数。 Be sure to be lenient, nobody likes to be off by 1E-15 and be reminded about it. 一定要宽容,没有人喜欢在1E-15之前离开并被提醒。 You can simply convert to Decimal in the attribute constructor. 您可以在属性构造函数中简单地转换为Decimal。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM