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



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



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


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



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



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


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




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




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



Даже если я настрою атрибут следующим образом:



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


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



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

3 ответов:

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

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

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

Например:

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

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

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

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

Comments

    Ничего не найдено.