「10進数」が有効な属性パラメータータイプではないのはなぜですか?


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は大丈夫なのに、decimalは大丈夫ではないのか、誰に教えてもらえますか。


回答:


139

これはCLRの制限です。属性パラメーターとして使用できるのは、プリミティブ定数またはプリミティブの配列のみです。理由は、属性は完全にメタデータにエンコードする必要があるためです。これは、ILでコーディングされているメソッド本体とは異なります。MetaDataを使用しても、使用できる値の範囲が厳しく制限されるだけです。CLRの現在のバージョンでは、メタデータ値はプリミティブ、null、タイプ、およびプリミティブの配列に制限されています(マイナーなものを見逃している可能性があります)。

撮影このことにより、答えJaredPar

基本タイプはプリミティブタイプではないため、10進数はメタデータで表すことができないため、属性パラメーターにすることができません。


34
小数がCLRでプリミティブ型と見なされないのはなぜですか?
koumides

10
@koumides答えは128ビットなので、タイプが大きすぎて1つのCPUレジスタで表現できないと
思います

2
では、属性のプロパティとして文字列が許可されているのはなぜですか?「プリミティブの配列」カテゴリに含まれると思いますが、ヒープが割り当てられています(参照型)...
Steztric

文字列は、まったく異なる方法で処理される参照型であるためです。
CarstenSchütte2016

2
@Sorenこれは真実ではなく、Enumサポートされています。現在、2つのカスタム属性があり、1つは2つの列挙型で、もう1つは列挙型の配列です。
フランク

60

スペックから:

属性クラスの定位置パラメーターと名前付きパラメーターのタイプは、以下の属性パラメータータイプに制限されています。

  • 次のいずれかのタイプ:boolbytechardoublefloatintlongsbyteshortstringuintulongushort
  • タイプobject
  • タイプSystem.Type
  • enum型。パブリックアクセシビリティがあり、入れ子になっている型(存在する場合)にもパブリックアクセシビリティ(属性仕様)がある場合。
  • 上記のタイプの1次元配列。

10
正解ですが、仕様の古いバージョンを引用していることに注意してください。C#バージョン3.0、4.0、および5.0では、typeを持つこともできますsbyteushortuintulong。そして、それは大丈夫だと思われます。しかし、それでもdecimal許可されません:-(
Jeppe Stig Nielsen

1
@JeppeStigNielsenスペックリンクと引用を更新しました
Ohad Schneider

6
ヌル可能プリミティブもサポートされていません。
KTCO 2018

2

この問題に対する答えは、文字列を使用することです。これは、アトミックタイプではなくても属性として許可されます。丸めを行うと結果の精度が低下するため、doubleは使用しないでください。

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

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

private decimal minimumValueDecimal;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.