2009-09-12 6 views
20

Если у меня есть перечисление как этотПочему 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

Хотя изначально я наткнулся на это в .NET 3.5 VS2008 это еще не работает в VS2010 Beta1. –

ответ

26

Голодные? равно NULLABLE < Голодные >, который с точки зрения означает, что

[Hunger(NullableHungerLevel = Hungry.CouldEatMySocks)] 

равно

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

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

+0

Теперь, когда вы это объясняете это вроде очевидно! –

19

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

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

    public sealed class HungerAttribute : Attribute 
    { 
    private readonly Hungry? _HungerLevel; 
    public Hungry? HungerLevel { get { return _HungerLevel; } } 

    public bool IsNull { get { return !_HungerLevel.HasValue; } }   

    public HungerAttribute() 
    { 
    } 

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

    public enum Hungry { Somewhat, Very, CouldEatMySocks } 
} 

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

+0

Вопрос не в том, «как мне это сделать», вопрос был «почему».Это никоим образом не отвечает на вопрос почему. –

+0

Да. Это работает. Я знаю, как обойти это, но я озадачен тем, почему он не работает как именованный параметр. Мне кажется непоследовательным. –

+0

Должен ли я удалить этот ответ? Cuz unfortunetely У меня нет ответов на причину :( – Shimmy

5

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

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

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

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

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

1

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

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

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

if(default(Hungry) == HungerLevel)//no value has been set 
Смежные вопросы