Чому "десяткова" не є дійсним типом параметра атрибута?


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

Хто може мені сказати, чому вдвічі гаразд, а десятків немає.


Відповіді:


139

Це обмеження CLR. В якості параметрів атрибутів можуть використовуватися лише примітивні константи або масиви примітивів. Причина полягає в тому, що атрибут повинен бути повністю закодований у метадані. Це відрізняється, ніж тіло методу, кодоване в ІЛ. Використання MetaData лише сильно обмежує область значень, які можна використовувати. У поточній версії CLR значення метаданих обмежуються примітивом, null, типами та масивами примітивів (можливо, пропустили другорядне).

Взяте з цієї відповіді ДжаредПар .

Десяткові знаки, хоча базовий тип, не є примітивним типом, а отже, не можуть бути представлені у метаданих, що заважає йому бути параметром атрибута.


35
Чому десяткові знаки не вважаються примітивними типами в CLR?
кумідес

10
@koumides Я вважаю, що відповідь - це тип занадто великий, щоб виразити його в одному реєстрі процесорів, оскільки це 128-
бітний

2
Гаразд, тому чому дозволені рядки як властивості атрибутів? Я припускаю, що він підпадає під категорію "масив примітивів", але він виділяється купою (тип посилання) ...
Steztric

Тому що рядки - це еталонні типи, які обробляються абсолютно різними.
Карстен Шютте

2
@Soren це неправда, Enumпідтримуються. Наразі у мене є 2 спеціальні атрибути, один - з 2 перерахунками, а інші - з масивом enum.
Франк

60

З специфікацій :

Типи позиційних та іменованих параметрів для класу атрибутів обмежені типом параметрів атрибутів, якими є:

  • Один з таких типів: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
  • Тип object.
  • Тип System.Type.
  • Тип перерахунку, якщо він має загальнодоступність та типи, в яких він вкладений (якщо такий є), також має загальнодоступність (специфікація атрибутів).
  • Одновимірні масиви вищевказаних типів.

10
Правильно, але зауважте, що ви цитуєте стару версію специфікації. У C версії 3.0, 4.0, і 5.0 #, стверджується , що вона також може мати тип sbyte, ushort, uint, ulong. І це, здається, працює добре. Але все одно decimalне дозволено :-(
Jeppe Stig Nielsen

1
@JeppeStigNielsen Я оновив специфікацію посилання та цитату
Охад Шнайдер,

6
Нульові примітиви також НЕ підтримуються.
KTCO

2

Відповідь на цю проблему полягає у використанні рядків, які дозволені як атрибути, незважаючи на те, що вони не є атомним. Не використовуйте парні пари, оскільки округлення зробить результати менш точними.

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

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

private decimal minimumValueDecimal;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.