为什么“十进制”不是有效的属性参数类型?


139

确实令人难以置信,但却是真实的。此代码将不起作用:

[AttributeUsage(AttributeTargets.Property|AttributeTargets.Field)]
public class Range : Attribute
{
    public decimal Max { get; set; }
    public decimal Min { get; set; }
}

public class Item
{
    [Range(Min=0m,Max=1000m)]  //compile error:'Min' is not a valid named attribute argument because it is not a valid attribute parameter type 
    public decimal Total { get; set; }  
}

尽管这可行:

[AttributeUsage(AttributeTargets.Property|AttributeTargets.Field)]
public class Range : Attribute
{
    public double Max { get; set; }
    public double Min { get; set; }
}

public class Item
{
    [Range(Min=0d,Max=1000d)]
    public decimal Total { get; set; }  
}

谁能告诉我为什么double可以,而十进制不可以。


Answers:


139

这是CLR限制。仅原始常量或原始数组可以用作属性参数。原因是属性必须完全在元数据中编码。这与用IL编码的方法主体不同。仅使用MetaData会严格限制可以使用的值的范围。在当前版本的CLR中,元数据值限于原语,空值,原语的类型和数组(可能遗漏了较小的一个)。

来自答案由JaredPar

基本类型不是原始类型的小数,因此不能在元数据中表示,这阻止了它成为属性参数。


35
为什么在CLR中不将小数视为原始类型?
koumides

10
@koumides我相信答案是类型太大而无法在单个CPU寄存器中表示,因为它是128位
Chris Marisic '16

2
好的,为什么要允许将字符串用作属性属性?我想它属于“原始数组”类别,但它是堆分配的(引用类型)...
Steztric

因为字符串是引用类型,它们的处理方式完全不同。
卡斯滕·舒特(CarstenSchütte)2016年

2
@Soren这不是真的,Enum受支持。我目前有2个自定义属性,一个带有2个枚举,另一个带有一个枚举数组。
法兰克

60

规格

属性类的位置和命名参数的类型限于属性参数类型,它们是:

  • 其中以下类型:boolbytechardoublefloatintlongsbyteshortstringuintulongushort
  • 类型object
  • 类型System.Type
  • 枚举类型,只要它具有公共可访问性,并且嵌套的类型(如果有)也具有公共可访问性(属性规范)。
  • 上述类型的一维数组。

10
正确,但是请注意,您引用的是旧版规范。在C#版本3.0,4.0和5.0,这是说,它也可以有型sbyteushortuintulong。看来一切正常。但仍然decimal不被允许:-(
Jeppe Stig Nielsen

1
@JeppeStigNielsen我已经更新了规格链接和报价
Ohad Schneider

6
也不支持可空基元。
KTCO

2

解决此问题的方法是使用字符串,尽管不是原子类型,也可以将其作为属性使用。不要使用双精度,因为四舍五入会使结果不太准确。

public String MinimumValue
{
    get
    {
        return minimumValueDecimal.ToString();
    }

    set
    {
        minimumValueDecimal = Decimal.Parse(value);
    }
}

private decimal minimumValueDecimal;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.