Warum ist "dezimal" kein gültiger Attributparametertyp?

139

Es ist wirklich unglaublich, aber echt. Dieser Code funktioniert nicht:

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

Während dies funktioniert:

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

Wer kann mir sagen, warum double in Ordnung ist, decimal nicht?

Cheng Chen
quelle

Antworten:

139

Dies ist eine CLR-Einschränkung. Nur primitive Konstanten oder Arrays von Primitiven können als Attributparameter verwendet werden. Der Grund dafür ist, dass ein Attribut vollständig in Metadaten codiert werden muss. Dies unterscheidet sich von einem Methodenkörper, der in IL codiert ist. Die Verwendung von MetaData schränkt den Umfang der Werte, die verwendet werden können, nur stark ein. In der aktuellen Version der CLR sind Metadatenwerte auf Grundelemente, Null, Typen und Arrays von Grundelementen beschränkt (möglicherweise wurde ein untergeordnetes Element übersehen).

Entnommen aus dieser Antwort von JaredPar .

Dezimalstellen, während ein Basistyp kein primitiver Typ ist, können daher nicht in Metadaten dargestellt werden, wodurch verhindert wird, dass er ein Attributparameter ist.

djdd87
quelle
34
Warum werden Dezimalstellen in der CLR nicht als primitive Typen betrachtet?
Koumides
10
@ Koumides Ich glaube, die Antwort ist, dass der Typ zu groß ist, um in einem einzelnen CPU-Register ausgedrückt zu werden, da er 128 Bit ist
Chris Marisic
2
OK, warum sind Zeichenfolgen als Attributeigenschaften zulässig? Ich nehme an, es fällt unter die Kategorie 'Array of Primitives', aber es ist Heap zugewiesen (Referenztyp) ...
Steztric
Weil Zeichenfolgen Referenztypen sind, die völlig anders behandelt werden.
Carsten Schütte
2
@Soren das ist nicht wahr, Enumwerden unterstützt. Ich habe derzeit 2 benutzerdefinierte Attribute, eines mit 2 Aufzählungen und die anderen mit einem Array von Aufzählungen.
Franck
60

Aus den Spezifikationen :

Die Arten von Positions- und benannten Parametern für eine Attributklasse sind auf die Attributparametertypen beschränkt, die:

  • Einer der folgenden Typen: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
  • Der Typ object.
  • Der Typ System.Type.
  • Ein Aufzählungstyp, sofern er öffentlich zugänglich ist und die Typen, in denen er verschachtelt ist (falls vorhanden), auch öffentlich zugänglich sind (Attributspezifikation).
  • Eindimensionale Arrays der oben genannten Typen.
Kobi
quelle
10
Richtig, aber beachten Sie, dass Sie eine alte Version der Spezifikation zitieren. In C # Versionen 3.0, 4.0 und 5.0, es wird festgestellt , dass es auch Art haben kann sbyte, ushort, uint, ulong. Und das scheint in Ordnung zu sein. Aber immer noch decimalnicht erlaubt :-(
Jeppe Stig Nielsen
1
@ JeppeStigNielsen Ich habe den Spezifikationslink und das Zitat aktualisiert
Ohad Schneider
6
Nullable Primitive werden ebenfalls NICHT unterstützt.
KTCO
2

Die Antwort auf dieses Problem besteht darin, Zeichenfolgen zu verwenden, die als Attribute zulässig sind, obwohl sie kein atomarer Typ sind. Verwenden Sie keine Doppelwerte, da durch Rundungen die Ergebnisse weniger genau werden.

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

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

private decimal minimumValueDecimal;
Daniel Barbalace
quelle