ограничения типа именованного параметра - PullRequest
7 голосов
/ 27 апреля 2011

Я проектирую пользовательский класс атрибутов.

public class MyAttr: Attribute
{
    public ValueRange ValRange { get; set; }
}

Затем я пытаюсь присвоить этот атрибут свойству в соседнем классе:

public class Foo
{
    [MyAttr(ValRange= new ValueRange())]
    public string Prop { get; set; }
}  

Однако компиляторжаловаться на следующее:

'ValRange' не является допустимым аргументом именованного атрибута, поскольку он не является допустимым типом параметра атрибута

Я также пытался преобразовать класс ValueRange вstruct в надежде, что этот тип значения может решить проблему.Есть ли способ обойти это?

Ответы [ 5 ]

21 голосов
/ 27 апреля 2011

Есть ли способ обойти это?

Нет.

Для получения более подробной информации я отсылаю вас к разделу 17.1.3 спецификации C # 4, которую я воспроизводлюздесь для вашего удобства:


Типы позиционных и именованных параметров для класса атрибута ограничены типами параметров атрибута, которые являются:

  • Один изследующие типы: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
  • Объект типа.
  • Тип System.Тип.
  • Тип enum при условии, что он имеет общедоступную доступность, а типы, в которые он вложен (если есть), также имеют общедоступную доступность.
  • Одномерные массивы вышеуказанных типов.

Аргумент конструктора или открытое поле, которое не имеет ни одного из этих типов, не может использоваться в качестве позиционного или именованного параметра в спецификации атрибута.


Помнитеточка атрибута равна в точке cвремя компиляции добавить информацию к метаданным, связанным с сущностью, на которую вы поместили атрибут.Это означает, что вся информация, связанная с этим атрибутом, должна иметь четко определенный, однозначный способ сериализации в метаданные и из них.Ограничивая набор допустимых типов небольшим подмножеством всех возможных типов, мы гарантируем, что компилятор всегда может выдавать допустимые метаданные, которые может понять потребитель.

2 голосов
/ 27 апреля 2011

Значения параметров атрибута должны быть разрешаемы во время компиляции (т.е. константы).

См. Attribute Parameter Types в MSDN:

Значения, передаваемые атрибутам, должны быть известны компилятору во время компиляции.

Если вы можете создать ValueRange, которая является константой, вы можете использовать ее.

1 голос
/ 01 мая 2011

Есть ли способ обойти это?

Да.

Ваш атрибут может использовать свойство Type, а затем использовать типы, которые реализуют определенный интерфейс , для которого код, обрабатывающий этот атрибут, должен будет принять и, таким образом, также создать неявный , но, надеюсь, документированный ,требование к своим клиентам:

public interface IValueRange {
  int Start { get; }
  int End { get; }
}
public class MyAttr : Attribute { 
  // The used type must implement IValueRange
  public Type ValueRangeType { get; set; } 
}

// ....

public class Foo { 

  class FooValueRange : IValueRange {
    public int Start { get { return 10; } }
    public int End { get { return 20; } }
  }
  [MyAttr(ValueRangeType = typeof(FooValueRange))]
  public string Prop { get; set; }

}

Это мало чем отличается от многих классов в пространстве имен System.ComponentModel, например DesignerAttribute.

1 голос
/ 27 апреля 2011

Атрибуты могут принимать только константы времени компиляции в качестве параметров (например, 3, «привет», typeof (MyClass), «путь к ресурсу, определяющему любые непостоянные данные, которые вам нужны»).

ПоследнийПример (передача типа), который я привел, может помочь вам разработать обходной путь (передать тип, реализующий интерфейс с нужным вам методом).

1 голос
/ 27 апреля 2011

Параметры атрибута должны быть значениями следующих типов (цитирование статьи):

  • Простые типы (bool, byte, char, short, int, long, float и double)
  • строка
  • System.Type
  • 1012 * перечисления *
  • объект (Аргумент к параметру атрибута объекта типа должен быть постоянным значением одного из вышеуказанных типов.)
  • Одномерные массивы любого из вышеперечисленных типов

Редактировать: Изменили «константу времени компиляции» на «значение», поскольку типы и массивы не являются константами (спасибо комментатору, который указал на это (и впоследствии по какой-то причине удалил свой комментарий ...))

...