我正在尝试使用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);
}
}
答案 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。