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

Почему параметр Nullable <T> не является допустимым параметром пользовательского атрибута, когда T является?

Если у меня есть перечисление, подобное этому

public enum Hungry
{
    Somewhat,
    Very,
    CouldEatMySocks
}

и настраиваемый атрибут, подобный этому

public class HungerAttribute : Attribute
{
    public Hungry HungerLevel { get; set; }
    public Hungry? NullableHungerLevel { get; set; }
}

Я могу это сделать

[Hunger(HungerLevel = Hungry.CouldEatMySocks)]
public class Thing1

но я не могу этого сделать

[Hunger(NullableHungerLevel = Hungry.CouldEatMySocks)]
public class Thing2

Он генерирует ошибку, в которой говорится: "NullableHungerLevel" не является допустимым аргументом атрибута имени, поскольку он не является допустимым типом параметра атрибута ".

Почему это не разрешено? Я понимаю, что в принципе это просто не входит в список принятых типов. Допустимыми типами являются примитивы, перечисления, строка, тип и одномерные массивы предыдущих типов.

Это просто старое правило, которое не обновилось, когда появился Nullable?

4b9b3361

Ответ 1

Hungry? равно Nullable<Hungry>, что в терминах означает, что

[Hunger(NullableHungerLevel = Hungry.CouldEatMySocks)]

равно

[Hunger(NullableHungerLevel = new Nullable<Hungry>(Hungry.CouldEatMySocks))]

Поскольку вы можете использовать только постоянные значения в аргументах именованных атрибутов, вам придется прибегнуть к решению Шимми.

Ответ 2

Чтобы обойти это, создайте еще один инициализатор в вашем атрибуте:

class Program
{
  [Hunger()]
  static void Main(string[] args)
  {
  }

  public sealed class HungerAttribute : Attribute
  {        
    public Hungry? HungerLevel { get; }
    public bool IsNull => !_HungerLevel.HasValue;

    public HungerAttribute()
    {
    }

    //Or:
    public HungerAttribute(Hungry level)
    {
      HungerLevel = level;
    }
  }

  public enum Hungry { Somewhat, Very, CouldEatMySocks }
}

Я понимаю, что вы не собираетесь использовать оба свойства.

Ответ 3

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

Nullable - это структура.

Поэтому этого не допускается.

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

Я не знаю никаких планов изменить это. Но я не могу объяснить, почему это ограничение существует.

Ответ 4

Вместо создания нулевого перечисления вы можете создать значение по умолчанию для этого перечисления. Enum выбирает значение по умолчанию из 1-го значения, поэтому установите для этого перечисление

public enum Hungry
{
    None,
    Somewhat,
    Very,
    CouldEatMySocks
}

в вашем коде вы можете сделать это, чтобы проверить значение null

if(default(Hungry) == HungerLevel)//no value has been set