Что на самом деле делает атрибут [Flags]?

Что на самом деле делает применение [Flags]?

Я знаю, что он изменяет поведение Enum.ToString, но делает ли что-нибудь еще ? (например, другое поведение компилятора или среды выполнения и т. д.)


Изменить: да, я знаю, что он документирует тот факт, что перечисление предназначено для использования в качестве побитовых флагов, и что более логично применить его к битовым флагам. . Однако я спрашивал больше о конкретных изменениях в поведении, а не об общих методах программирования.


person user541686    schedule 05.05.2011    source источник
comment
Взгляните на msdn.microsoft.com/en-us/library/ms229062. aspx   -  person SQLMenace    schedule 05.05.2011
comment
@SQLMenace: Это просто говорит о том, когда я должен его применять и как мне писать свой код, а не если он меняет поведение чего-либо. : \   -  person user541686    schedule 05.05.2011
comment
+1 Я спрашивал себя много раз   -  person Chris Marisic    schedule 05.05.2011
comment
Я бы хотел, чтобы @Eric Lippert прокомментировал это.   -  person Dave Ziegler    schedule 06.05.2011


Ответы (6)


Из статьи в MSDN:

Интересно отметить, что при указании Flags методы Parse и Format имеют расширенные возможности.

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

person devio    schedule 05.05.2011
comment
+1 пока что кажется лучшим ответом. Я понятия не имел, что это меняет поведение _1 _... - person user541686; 05.05.2011

См. Сообщение Дэвида М. Кина здесь . Похоже, это проблема языкового взаимодействия:

Хотя C # с радостью позволяет пользователям выполнять битовые операции с перечислениями без FlagsAttribute, Visual Basic этого не делает. Поэтому, если вы открываете типы для других языков, пометка перечислений с помощью FlagsAttribute - хорошая идея; это также проясняет, что члены перечисления предназначены для совместного использования.

С Уважением

Дэйвид

person Dave Ziegler    schedule 05.05.2011
comment
+1 отличный (и неожиданный) ответ. :) (Хотя я должен признать, что для меня .NET - это в значительной степени разные формы одного и того же языка. Тем не менее, все же отличный ответ.) - person user541686; 05.05.2011
comment
ваш ответ был бы даже лучше, если бы вы скопировали содержание этого сообщения в свой ответ. - person Daniel Pryden; 06.05.2011
comment
Хммм ... Я только что проверил, и VB не назначает автоматически перечисления [flag] как степени двойки, как следует из этого поста. Увеличивает их обычным образом - на 1. - person Brian MacKay; 06.05.2011

Вот список конкретных поведенческих различий:

  • Установка перечисления с [flags] на None очищает все флаги.
  • Метод HasFlags работает только при наличии этого атрибута.
  • Как сказал Devio, это меняет возможности методов Parse и Format. Он добавил ссылку на эту статью. По-видимому, это также влияет на то, что показано в отладчиках.
  • Я думал, что [флаги], вероятно, повлияли на генерацию кода в веб-сервисах, но похоже, что это не так .
  • Чтобы было ясно, побитовые операции разрешены для любого перечисления, с [флагами] или без него. Но его использование - лучшая практика.

Дополнительные сведения: http://msdn.microsoft.com/en-us/library/ms229062.aspx

person Brian MacKay    schedule 05.05.2011

Если вы спросите, что он делает под капотом, насколько мне известно, он меняет метод ToString (), ничего другого.

В .Net 4 у вас есть HasFlags -метод для проверьте наличие конкретных флагов. Если я правильно интерпретирую msdn, вы должны использовать атрибут flags для использования этого метода. Но я не пробовал.

person HCL    schedule 05.05.2011

На практике одно из применений, которые я использую, - это указание нескольких статусов. Это упрощение некоторого кода, оценивающего результаты тестирования. Тест может быть удовлетворительным, или у него может быть несколько причин, по которым он не прошел. Преимущество, которое это дает, состоит в том, что у меня есть один метод, который оценивает "правильность" тестов, и этот метод может указать все возможные условия отказа одним возвратом. Может быть, это не лучший дизайн, но в данном случае он работает.

[Flags]
public enum ResultStatusEnum
{
    Ok = 0x1,
    SampleInvalid = 0x2,
    DirectionInvalid = 0x4,
    TestIsNotValid = 0x8
}

Вы устанавливаете это так:

ResultStatusEnum res = ResultStatusEnum.SampleInvalid | ResultStatusEnum.DirectionInvalid;

Недостатком является то, что проверка значений перечисления становится обременительной. Это не (обязательно) сработает:

res == ResultStatusEnum.Ok

Это нужно сделать, чтобы проверить:

ResultStatusEnum.SampleInvalid == (res & ResultStatusEnum.SampleInvalid)

В этом случае нелогично иметь ResultStatusEnum.Ok & ResultStatusEnum.SampleInvalid, но я просто убеждаюсь, что это не тот случай, когда я использую перечисление.

person Tim Coker    schedule 05.05.2011
comment
Да, но если он не оформлен как таковой, другие языки могут / не могут правильно обрабатывать перечисление. Если это все на C #, думаю, это не имеет особого значения. Но когда я его вижу, я ожидаю такого использования. Без него я НЕ НАДЕЮСЬ увидеть немного мудрого использования. Так что это полезно для удобочитаемости. - person Tim Coker; 05.05.2011
comment
Я полагаю, это зависит от того, что вы подразумеваете под ручкой. Они, безусловно, могли бы выполнять с ними побитовые операции таким же образом, но будут ли они разрешать их в первую очередь, кажется проблемой, в зависимости от того, что Чарльз опубликовал сообщение. - person user541686; 05.05.2011

Flags дает возможность использовать перечисление для нескольких значений.

Рассмотрим ситуацию, когда вы хотите использовать флажки для разных ситуаций, но не хотите создавать разные столбцы в базе данных. Если у вас есть 20 флажков, вам нужно будет создать 20 столбцов в базе данных с помощью bool. Но с помощью флагов вы можете создать один столбец и использовать это значение для хранения в столбце. Запустите этот пример в консоли, чтобы лучше понять его.

class Program
{
    static void Main(string[] args)
    {
        //Set the features that you require for car. Consider it as checked in the UI.
        CarFeatures carFeatures = CarFeatures.AC | CarFeatures.Autopilot| CarFeatures.Sunroof;

        //Do the backend logic
        if (carFeatures.HasFlag(CarFeatures.Autopilot))
        {
            //Show Autopilot cars
        }
        //See the what carfeatures are required
        Console.WriteLine(carFeatures);
        //See the integer value of the carfeatures
        Console.WriteLine((int)carFeatures);
        Console.ReadLine();
    }
}

[Flags]
public enum CarFeatures
{
    AC=1,
    HeatedSeats= 2,
    Sunroof= 4,
    Autopilot= 8,
}

Различная комбинация всегда дает вам уникальный номер, который C # отслеживает, чтобы найти все, что помечено.

person John Kuriakose    schedule 21.08.2018