Mengapa "desimal" bukan jenis parameter atribut yang valid?

142

Ini benar-benar tidak bisa dipercaya tapi nyata. Kode ini tidak akan berfungsi:

[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; }  
}

Saat ini berfungsi:

[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; }  
}

Siapa yang bisa memberi tahu saya mengapa dua kali lipat tidak apa-apa sedangkan desimal tidak.

Cheng Chen
sumber

Jawaban:

143

Ini adalah pembatasan CLR. Hanya konstanta primitif atau array primitif yang dapat digunakan sebagai parameter atribut. Alasannya adalah bahwa atribut harus dikodekan seluruhnya dalam metadata. Ini berbeda dari badan metode yang dikodekan dalam IL. Menggunakan MetaData hanya sangat membatasi ruang lingkup nilai yang dapat digunakan. Dalam versi CLR saat ini, nilai metadata dibatasi ke primitif, null, jenis dan array primitif (mungkin melewatkan yang kecil).

Diambil dari ini jawaban oleh JaredPar .

Desimal sementara tipe dasar bukanlah tipe primitif dan karenanya tidak dapat direpresentasikan dalam metadata yang mencegahnya menjadi parameter atribut.

djdd87.dll
sumber
36
Mengapa desimal tidak dianggap sebagai tipe primitif di CLR?
koumides
10
@koumides saya yakin jawabannya adalah tipe yang terlalu besar untuk diekspresikan dalam satu register CPU karena 128bit
Chris Marisic
3
Oke, jadi mengapa string diizinkan sebagai properti atribut? Saya kira itu termasuk dalam kategori 'array primitif' tetapi itu adalah tumpukan yang dialokasikan (tipe referensi) ...
Steztric
Karena string adalah tipe referensi yang ditangani sangat berbeda.
Carsten Schütte
2
@Soren ini tidak benar, Enumdidukung. Saat ini saya memiliki 2 atribut khusus, satu dengan 2 enum dan yang lainnya dengan array enum.
Franck
60

Dari spesifikasi :

Jenis parameter posisi dan nama untuk kelas atribut dibatasi untuk jenis parameter atribut, yaitu:

  • Salah satu jenis berikut: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
  • Tipe object .
  • JenisnyaSystem.Type .
  • Tipe enum, asalkan memiliki aksesibilitas publik dan tipe yang menumpuknya (jika ada) juga memiliki aksesibilitas publik (spesifikasi atribut).
  • Array berdimensi tunggal dari tipe di atas.
Kobi
sumber
10
Benar, tetapi perhatikan bahwa Anda mengutip spesifikasi versi lama. Dalam C # versi 3.0, 4.0, dan 5.0, dinyatakan bahwa hal itu juga dapat memiliki jenis sbyte, ushort, uint, ulong. Dan itu tampaknya berhasil. Tapi tetap decimaltidak diperbolehkan :-(
Jeppe Stig Nielsen
1
@JeppeStigNielsen Saya telah memperbarui tautan spesifikasi dan kutipan
Ohad Schneider
6
Primitif nullable juga TIDAK didukung.
KTCO
2

Jawaban untuk masalah ini adalah dengan menggunakan string, yang diizinkan sebagai atribut meskipun bukan merupakan tipe atom. Jangan gunakan ganda karena pembulatan akan membuat hasil kurang akurat.

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

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

private decimal minimumValueDecimal;
Daniel Barbalace
sumber