简体   繁体   English

将标志枚举用作普通枚举

[英]Use Flags Enum as a normal Enum

Is there a way to optionally force a [Flags] enum to be "non-Flags" for specific uses? 有没有一种方法可以选择性地将[Flags]枚举强制为“ Flags”以用于特定用途?

For example, say I have 例如说我有

enum MyEnum {
     X ,
     Y , 
     Z 
 }

Now let's say I have two classes A and B . 现在假设我有两个班级AB Class B will mostly be used within an IEnumerable<B> . B类将主要在IEnumerable<B> Class A is responsible for parsing this list, but only when the enum matches a particular value; 类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
               }
           }
      }
 }

Now suppose I want class A to be able to work with multiple types of B. I could add the [Flags] attribute to my enum and do something like this: 现在假设我希望类A能够与多种类型的B一起使用。我可以将[F​​lags]属性添加到我的枚举中,并执行以下操作:

[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
               }
           }
      }
 }

However, class B's MyProperty can now be used as a flag, which is a problem because there's no such thing as a MyEnum.X | MyEnum.Y 但是,现在可以将类B的MyProperty用作标志,这是一个问题,因为没有MyEnum.X | MyEnum.Y MyEnum.X | MyEnum.Y in the context of B.MyProperty . MyEnum.X | MyEnum.Y中的B.MyProperty It makes sense within A because I am targeting various kinds of class B. A之内有意义是因为我针对的是各种B类。

The work around that I've come up with is this: 我提出的解决方法是:

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
               }
           }
      }
 }

While this works, it's definitely messy. 虽然这有效,但绝对是一团糟。 I now have to keep track of two different enums. 我现在必须跟踪两个不同的枚举。 Any change I make in one, I have to make in the other and I have to make sure that the values are syncronized. 我对一个进行任何更改,我必须对另一个进行更改,并且必须确保值已同步。 On top of that I now have to cast to MyEnumTarget to be able to pass the value to Enum.HasFlag . 最重要的是,我现在必须转换为MyEnumTarget才能将值传递给Enum.HasFlag Granted I could do bit-wise operations but then its not always so obvious what the intent is. 当然,我可以进行按位操作,但意图并不总是那么明显。 Either way, I'd still need two "matching" enums. 无论哪种方式,我仍然需要两个“匹配”的枚举。

Is there no better way to do to this? 有没有更好的办法做到这一点? Is there some way to use a single enum type and force some sort of [NoFlags] attribute on B.MyProperty . 是否有某种方式使用单个枚举类型,并迫使某种[NoFlags]属性上B.MyProperty Or is having the two enums considered the best way / good practice? 还是让两个枚举被认为是最佳方法/最佳实践?

I'm using C#6.0 if that matters 如果重要,我正在使用C#6.0

Fundamentally, each enum type either is designed to have be a bit mask, or isn't. 从根本上说,无论是设计成具有每个枚举类型是位掩码,或者不是。 Options you might consider: 您可能会考虑的选项:

  • Two separate enums, as per your code 根据您的代码两个独立的枚举
  • One non-flags enum, but make A.Property a List<MyEnum> or similar 一个非标志枚举,但将A.Property List<MyEnum>或类似名称
  • One flags enum, but make the B.Property setter validate that only a single bit is set, throwing an ArgumentException otherwise 一个标志枚举,但使B.Property设置程序验证仅设置了一个位,否则抛出ArgumentException

What's different between the two uses? 两种用途有什么不同? It sounds like these should be two different enums because their meanings are different. 听起来这应该是两个不同的枚举,因为它们的含义不同。 The contracts of their use are different. 它们的使用合同不同。 If these were classes, I would suggest applying the Interface Segregation Principle , because they are used in a different way by different clients. 如果这些是类,我建议您应用接口隔离原则 ,因为不同的客户端以不同的方式使用它们。

As these are enums, you can either wrap them in classes with interface segregation, or at least distinguish between the two enums. 由于这些是枚举,因此可以将它们包装在具有接口隔离​​的类中,或者至少区分两个枚举。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM