Есть ли шаблон или метод в C #, чтобы проверить, является ли опция (int 1,2,4,8, ...) истинной или ложной - PullRequest
5 голосов
/ 20 мая 2011

Мне нравится писать enum или integer для передачи опции моим методам. Есть ли шаблон или метод в C #, чтобы проверить, является ли (int 1,2,4,8, ...) опция true или false. Я думаю, что это должно быть легко возможно с помощью бинарных функций.

class Program
{
    public enum Option
    {
        Option_A = 1,
        Option_B = 2,
        Option_C = 4,
        Option_D = 8,
    }

    static void Main(string[] args)
    {
        int activeOption = 5; // Means I activeted the Option_A and Option_C
        if (IsOption(activeOption, Option.Option_A)) { /*do work*/ }
        if (IsOption(activeOption, Option.Option_B)) { /*do work*/ }
        if (IsOption(activeOption, Option.Option_C)) { /*do work*/ }
        if (IsOption(activeOption, Option.Option_D)) { /*do work*/ }
    }

    private static bool IsOption(int activeOption, Option option)
    {
        /*Evaluate if IsOption is true or false*/
        throw new NotImplementedException();
    }
}

EDIT

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

Ответы [ 5 ]

10 голосов
/ 20 мая 2011

Поскольку ваше перечисление содержит флаги (или, если вы предпочитаете, это битовое поле), вы должны добавить к нему FlagsAttribute:

[Flags]
public enum Option
{
    Option_A = 1,
    Option_B = 2,
    Option_C = 4,
    Option_D = 8,
}

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

if(((Option)activeOption & Option.Option_A) != Option.Option_A) //...

Если вы хотите скрыть эту гадость, прочитайте статью, на которую есть ссылка в Smudge202-ответ . Если вы используете .NET 4, вам даже не нужно этого делать: проверьте ответ sehe .

Но вам действительно следует попытаться использовать переменную типа Option напрямую и объединить параметры с побитовым оператором или:

Option activeOption = Option.Option_A | Option.Option_C;

Конечно, использование этой схемы ограничивает количество вариантов, которые вы можете создать. Если вы оставите все как есть, вы можете создать только 32 различных параметра, потому что int (базовый тип перечисления по умолчанию) имеет только 32 бита. Если вы используете long, у вас может быть 64 различных варианта:

[Flags]
public enum Option : long
{
    Option_A = 1,
    Option_B = 2,
    Option_C = 4,
    Option_D = 8,
    // blah blah
}

Однако, если вам нужно произвольное количество опций, возможно, пришло время изменить стратегии. Вы можете создать пользовательский тип, который будет вести себя как перечисление, но вам, вероятно, будет лучше, если использовать просто обычное перечисление без флагов и HashSet<Option>.

public enum Option
{
    Option_A = 1, // notice the sequential values now
    Option_B = 2,
    Option_C = 3,
    Option_D = 4,
}

HashSet<Option> options = new HashSet<Option> { Option.Option_A, Option.Option_C };
if(options.Contains(Option.Option_A)) // ...
3 голосов
/ 20 мая 2011

Используйте побитовое И, чтобы проверить, установлены ли биты в option в activeOption.Вам также нужно сделать оба параметра одинаковыми, чтобы оператор работал (вы все равно проверяете биты в Option битовой маске):

private static bool IsOption(Option activeOption, Option option)
{
    return (activeOption & option) == option;
}
2 голосов
/ 20 мая 2011

Помимо упомянутого атрибута Flags, в C # есть метод Enum.HasFlag

using System;

[Flags] public enum DinnerItems {
   None = 0,
   Entree = 1,
   Appetizer = 2,
   Side = 4,
   Dessert = 8,
   Beverage = 16, 
   BarBeverage = 32
}

public class Example
{
   public static void Main()
   {
      DinnerItems myOrder = DinnerItems.Appetizer | DinnerItems.Entree |
                            DinnerItems.Beverage | DinnerItems.Dessert;
      DinnerItems flagValue = DinnerItems.Entree | DinnerItems.Beverage;
      Console.WriteLine("{0} includes {1}: {2}", 
                        myOrder, flagValue, myOrder.HasFlag(flagValue));
   }
}
// The example displays the following output:
//    Entree, Appetizer, Dessert, Beverage includes Entree, Beverage: True
1 голос
/ 20 мая 2011

Если вы используете .NET 4.0, вы можете использовать HasFlag.

static void Main(string[] args)
{
    Option activeOption = (Option)5; // Means I activeted the Option_A and Option_C
    if (activeOption.HasFlag(Option.Option_A)) { /*do work*/ }
    if (activeOption.HasFlag(Option.Option_B)) { /*do work*/ }
    if (activeOption.HasFlag(Option.Option_C)) { /*do work*/ }
    if (activeOption.HasFlag(Option.Option_D)) { /*do work*/ }
}
1 голос
/ 20 мая 2011

Взгляните на перечисления, использующие атрибуты флага.

http://www.codeproject.com/Articles/37921/Enums-Flags-and-Csharp-Oh-my-bad-pun.aspx

...