2015-12-14 2 views
0

Есть ли способ необязательно форматировать перечисление [Flags] как «не-флаги» для определенных целей?Использовать флаги Enum в качестве обычного Enum

Например, у меня есть

enum MyEnum { 
    X , 
    Y , 
    Z 
} 

Теперь, скажем, у меня есть два класса A и B. Класс B будет в основном использоваться в пределах IEnumerable<B>. Класс A отвечает за разбор этого списка, но только тогда, когда перечисление соответствует определенному значению;

class B { 
     MyEnum MyProperty { get; set; } 
    } 

class A { 
     MyEnum Target = MyEnum.C; 
     void DoSomething(IEnumerable<B> list) { 

      for (var b in list) { 
       if (b.MyProperty == this.Target) { 
        // Do Some Work 
       } 
      } 
     } 
} 

Теперь предположим, что я хочу, класс А, чтобы иметь возможность работать с несколькими типами B. Я мог бы добавить [Flags] атрибут моего перечисления и сделать что-то вроде этого:

[Flags] 
enum MyEnum { 
    None = 0, 
    X = 1, 
    Y = 2, 
    Z = 4 
} 


class B { 
     MyEnum MyProperty { get; set; } 
    } 

class A { 
     MyEnum Target = MyEnum.X | MyEnum.Z; 
     void DoSomething(IEnumerable<B> list) { 

      for (var b in list) { 
       if (this.Target.HasFlag(b.MyProperty)) { 
        // Do Some Work 
       } 
      } 
     } 
} 

Однако, класс B's MyProperty теперь может использоваться как флаг, что является проблемой, поскольку в контексте B.MyProperty нет такой вещи, как MyEnum.X | MyEnum.Y. Это имеет смысл в A, потому что я целенаправленное воздействие на различные виды класса B.

Обходной, что я придумал это:

enum MyEnum { 
    None = 0, 
    X = 1, 
    Y = 2, 
    Z = 4 
} 

[Flags] 
enum MyEnumTarget { 
    None = 0, 
    X = 1, 
    Y = 2, 
    Z = 4 
} 

class B { 
     MyEnum MyProperty { get; set; } 
    } 

class A { 
     MyEnumTarget Target = MyEnumTarget.X | MyEnumTarget.Z; 
     void DoSomething(IEnumerable<B> list) { 

      for (var b in list) { 
       if (this.Target.HasFlag((MyEnumTarget)b.MyProperty)) { 
        // Do Some Work 
       } 
      } 
     } 
} 

В то время как это работает, это, безусловно, грязное. Теперь мне нужно отслеживать два разных перечисления. Любое изменение, которое я делаю в одном, я должен сделать в другом, и я должен убедиться, что значения синхронизированы. Кроме того, теперь мне нужно отправить MyEnumTarget, чтобы передать значение Enum.HasFlag. Конечно, я мог бы выполнять побитые операции, но тогда это не всегда так очевидно, что это за намерение. В любом случае, мне все равно потребуется два «совпадающих» перечисления.

Нет ли лучшего способа сделать это? Можно ли использовать один тип перечисления и заставить какой-то атрибут [NoFlags] на B.MyProperty. Или есть два перечисления, которые считаются наилучшим способом/хорошей практикой?

Я использую C# 6.0, если это имеет значение

+1

Имейте в виду, что флаги перечислены или нет, * любое * целочисленное значение может быть введено в значение типа 'MyEnum'. Вам необходимо проверить значения, с которыми вы работаете, в любом случае. Перечисления не ограничены только определенными значениями. –

+0

Я знаю, что любое целое может быть применено к этому. Однако я не беспокоюсь о том, чтобы кто-то присвоил ему ценность. Все это является внутренним для сборки и не подвергается никому другому. Внутри мы знаем, как его использовать, и по существу не будем злоупотреблять свойствами ... его больше как предосторожность для тех, кто вносит изменения в будущем. – pinkfloydx33

ответ

1

В принципе, каждый тип перечисления либо является разработан, чтобы быть битовую маску, или нет. Опции Вы могли бы рассмотреть:

  • Два отдельных перечислений, в соответствии с вашим кодом
  • один не флаги перечислений, но сделать A.Property в List<MyEnum> или аналогичном
  • Один флаги перечисление, но сделать B.Property сеттера подтверждение того, что только один бит установлен, метание ArgumentException в противном случае
+0

Мой первый ответ Джон Скит !!! Я рассмотрел подход «Список». Как я упоминал в своем комментарии выше, это все внутреннее для сборки; свойства не будут подвергаться вызову этих классов; они будут установлены только мной и/или моей командой по мере разработки нашего приложения. Прямо сейчас во время разработки мы знали бы, что присваиваем только одиночные значения. Моя забота была больше для следующего парня, который присоединяется к нашей команде или через год, если мы забудем - в основном, предосторожность. – pinkfloydx33

+0

@ pinkfloydx33: Похоже, вы должны проверить его на сеттере тогда :) (или использовать коллекцию ...) –

0

В чем разница между этими двумя способами? Похоже, что эти должны быть двумя разными перечислениями, потому что их значения различны. контрактов их использования разные. Если бы это были классы, я бы предложил применить Interface Segregation Principle, потому что они используются по-разному разными клиентами.

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

Смежные вопросы