Атрибуты и параметры именованного / необязательного конструктора не работают - PullRequest
22 голосов
/ 19 ноября 2011

У меня пользовательский атрибут, определенный так:

  [AttributeUsage(AttributeTargets.Field)]
  public class EnumDisplayAttribute : Attribute
  {
    public string Description { get; private set; }
    public string Code { get; private set; }

    public EnumDisplayAttribute(string description = null, string code = null)
    {
      Description = description;
      Code = code;
    }
  }

Оба параметра конструктора являются необязательными.

При использовании этого атрибута в поле, подобном этому

  public enum TransactionType
  {
    [EnumDisplay(code: "B")] 
    Bill,
    [EnumDisplay(description: null, code: "C")]
    CashReceipt,
  }

В редакторе кода я не вижу никаких кривых, но я вижу неопределенную ошибку без номера строки в столбце. Сообщение об ошибке:

ошибка CS0182: аргумент атрибута должен быть константным выражением, typeof expression или выражение создания массива типа параметра атрибута

Нажатие на ошибку ничего не делает. То есть вы не перейдете на сайт с ошибкой (очевидно, так как нет номера строки и столбца).

даже если я настроил атрибут так:

[EnumDisplay("This is a Bill")] 

Компилятору это не нравится.

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

Конечно, если я использую этот атрибут как обычный класс, вот так:

var enumDisplayAttribute = new EnumDisplayAttribute();
enumDisplayAttribute = new EnumDisplayAttribute(description: "This is a Bill");
enumDisplayAttribute = new EnumDisplayAttribute(code: "B");
enumDisplayAttribute = new EnumDisplayAttribute(description: "This is a Bill", code: "B");
enumDisplayAttribute = new EnumDisplayAttribute("This is a Bill", "B");
enumDisplayAttribute = new EnumDisplayAttribute("This is a Bill");

Компилятор принимает любой из вышеперечисленных "стилей".

Конечно, я что-то упустил или мой мозг просто не работает.

Ответы [ 3 ]

28 голосов
/ 19 ноября 2011

Дополнительные параметры были добавлены в C # после того, как дополнительные значения для атрибутов уже существовали в C #.Следовательно, для необязательных параметров атрибута вы должны прибегнуть к специфическому для атрибута синтаксису:

[AttributeUsage(AttributeTargets.Field)]
public class EnumDisplayAttribute : Attribute
{
    public string Description { get; set; }
    public string Code { get; set; }

    public EnumDisplayAttribute()
    {
    }
}

public enum TransactionType
{
    [EnumDisplay(Code = "B")] 
    Bill,
    [EnumDisplay(Description = null, Code = "C")]
    CashReceipt,
}

Как видите, конечный результат фактически тот же, но вместо использования именованных аргументов вы используетеименованные свойства (где синтаксис, такой как [EnumDisplay(Description = null, Code = "C")], возможен только в объявлениях атрибутов).

Еще один способ думать об этом - объявления атрибутов «заимствовали» свой синтаксис из вызовов методов / конструкторов, но объявления атрибутов не сами по себе вызовы методов, поэтому они не получают все те же функции, что и методы.

5 голосов
/ 14 февраля 2012

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

Например:

[AttributeUsage(AttributeTargets.Field)]
public class SampleAttribute : Attribute
{
    public string MandatoryProperty { get; private set; }
    public string OptionalProperty { get; private set; }

    // we use an overload here instead of optional parameters because 
    // C# does not currently support optional constructor parameters in attributes
    public SampleAttribute(string mandatoryProperty)
        : this(mandatoryProperty, null)
    {
    }

    public SampleAttribute(string mandatoryProperty, string optionalProperty)
    {
        MandatoryProperty = mandatoryProperty;
        OptionalProperty = optionalProperty;
    }
}
3 голосов
/ 19 ноября 2011

Необязательные параметры на самом деле не являются необязательными, в сигнатуре метода есть все аргументы, а атрибуты являются специальными (существовали до необязательных параметров и имеют разные правила при применении в качестве атрибута (например, рассмотрим, кто вызывает конструктор атрибута)).Однако я полагаю, что поддержка будет добавлена ​​в будущем.

Пока, если вы хотите добиться дополнительного эффекта, попробуйте следующее:

[AttributeUsage(AttributeTargets.Field)]
public class EnumDisplayAttribute : Attribute
{
  public string Description { get; set; }
  public string Code { get; set; }

}

И примените так:

[EnumDisplay(Description = null, Code = "C")]
private object _aField;
...