Почему параметр 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?
Ответы
Ответ 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