Perché "decimale" non è un tipo di parametro di attributo valido?


139

È davvero incredibile ma reale. Questo codice non funzionerà:

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

Mentre funziona:

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

Chi può dirmi perché il doppio è OK mentre il decimale no.


1
possibile duplicare i valori decimali
nawfal,

Risposte:


139

Questa è una restrizione CLR. Solo le costanti o le matrici primitive di primitive possono essere utilizzate come parametri di attributo. Il motivo è che un attributo deve essere codificato interamente in metadati. Questo è diverso da un corpo di metodo che è codificato in IL. L'uso di MetaData limita fortemente l'ambito dei valori che possono essere utilizzati. Nell'attuale versione del CLR, i valori dei metadati sono limitati a primitive, null, tipi e matrici di primitive (potrebbe esserne mancata una minore).

Tratto da questa risposta di JaredPar .

I decimali mentre un tipo di base non sono un tipo primitivo e quindi non possono essere rappresentati nei metadati che ne impediscono di essere un parametro di attributo.


35
Perché i decimali non sono considerati tipi primitivi nel CLR?
Koumides,

10
@koumides Credo che la risposta sia che il tipo è troppo grande per essere espresso in un singolo registro della CPU in quanto è a 128 bit
Chris Marisic,

2
OK, quindi perché le stringhe sono consentite come proprietà degli attributi? Suppongo che rientri nella categoria "array di primitivi" ma è allocato in heap (tipo di riferimento) ...
Steztric,

Perché le stringhe sono tipi di riferimento che sono gestiti in modo completamente diverso.
Carsten Schütte,

2
@Soren questo non è vero, Enumsono supportati. Al momento ho 2 attributi personalizzati uno con 2 enum e gli altri con una matrice di enum.
Franck,

60

Dalle specifiche :

I tipi di parametri posizionali e denominati per una classe di attributi sono limitati ai tipi di parametri di attributo, che sono:

  • Uno dei seguenti tipi: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong,ushort .
  • Il tipo object .
  • Il tipoSystem.Type .
  • Un tipo enum, a condizione che abbia accessibilità pubblica e che i tipi in cui è nidificato (se presente) abbiano anche accessibilità pubblica (specifica dell'attributo).
  • Matrici monodimensionali dei tipi precedenti.

10
Corretto, ma nota che stai citando una vecchia versione della specifica. In C # versioni 3.0, 4.0 e 5.0, si afferma che può anche essere di tipo sbyte, ushort, uint, ulong. E questo sembra funzionare bene. Ma ancora decimalnon è permesso :-(
Jeppe Stig Nielsen,

1
@JeppeStigNielsen Ho aggiornato il collegamento e la citazione della specifica
Ohad Schneider,

6
Anche le primitive nullable NON sono supportate.
KTCO,

2

La risposta a questo problema è utilizzare le stringhe, che sono consentite come attributi nonostante non siano di tipo atomico. Non usare i doppi poiché l'arrotondamento renderà i risultati meno precisi.

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

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

private decimal minimumValueDecimal;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.