Подтвердить что ты не робот

Атрибуты и Named/необязательные параметры конструктора не работают

У меня есть настраиваемый атрибут:

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

Я не вижу в редакторе кода каких-либо squigglies, но я вижу неопределенную ошибку без номера строки File of column. Сообщение об ошибке:

error 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");

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

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

4b9b3361

Ответ 1

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

[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")] возможен только в объявлениях атрибутов).

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

Ответ 2

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

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

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

Ответ 3

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

Например:

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