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

Если у меня есть такое перечисление

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?

Ответы [ 4 ]

28 голосов
/ 13 сентября 2009

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

[Hunger(NullableHungerLevel = Hungry.CouldEatMySocks)]

равно

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

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

22 голосов
/ 13 сентября 2009

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

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

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

6 голосов
/ 13 сентября 2009

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

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

Поэтому там не разрешено.

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

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

3 голосов
/ 09 декабря 2016

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

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

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

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