Por que "decimal" não é um tipo de parâmetro de atributo válido?


139

É realmente inacreditável, mas real. Este código não funcionará:

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

Enquanto isso funciona:

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

Quem pode me dizer por que o dobro está OK e o decimal não.


Respostas:


139

Esta é uma restrição do CLR. Somente constantes primitivas ou matrizes de primitivas podem ser usadas como parâmetros de atributo. O motivo é que um atributo deve ser codificado inteiramente em metadados. Isso é diferente de um corpo de método que é codificado em IL. O uso de MetaData restringe apenas severamente o escopo dos valores que podem ser usados. Na versão atual do CLR, os valores de metadados são limitados a primitivos, nulos, tipos e matrizes de primitivos (pode ter faltado um menor).

Retirado desta resposta por JaredPar .

Os decimais enquanto um tipo básico não são primitivos e, portanto, não podem ser representados em metadados, o que impede que seja um parâmetro de atributo.


35
Por que decimais não são considerados tipos primitivos no CLR?
Koumides

10
@koumides Creio que a resposta é o tipo é muito grande para expressar em um único registo CPU como é de 128 bits
Chris Marisic

2
OK, então por que as strings são permitidas como propriedades de atributo? Suponho que ele se
enquadre

Porque strings são tipos de referência que são manipulados completamente diferentes.
Carsten Schütte

2
@ Soren isso não é verdade, Enumsão suportados. Atualmente, tenho 2 atributos personalizados, um com 2 enumerações e os outros com uma matriz de enumeração.
Franck

60

Das especificações :

Os tipos de parâmetros posicionais e nomeados para uma classe de atributo são limitados aos tipos de parâmetro de atributo, que são:

  • Um dos seguintes tipos: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
  • O tipo object.
  • O tipo System.Type.
  • Um tipo de enumeração, desde que tenha acessibilidade pública e os tipos em que está aninhado (se houver) também tenham acessibilidade pública (especificação de atributo).
  • Matrizes unidimensionais dos tipos acima.

10
Correto, mas observe que você está citando uma versão antiga da especificação. Em C # versões 3.0, 4.0 e 5.0, afirma-se que ele também pode ter tipo sbyte, ushort, uint, ulong. E isso parece funcionar bem. Mas ainda decimalnão é permitido :-(
Jeppe Stig Nielsen

1
@JeppeStigNielsen Eu atualizei o link especificação e cotação
Ohad Schneider

6
Primitivas anuláveis ​​também NÃO são suportadas.
KTCO 17/02

2

A resposta para esse problema é usar cadeias, que são permitidas como atributos, apesar de não serem do tipo atômico. Não use duplos, pois o arredondamento tornará os resultados menos precisos.

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

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

private decimal minimumValueDecimal;
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.