“多态枚举”数值如何判断?

枚举的作用就是用“字面量”的形式(附带智能提示)取代纯粹的数字化。假设某一个程序中有4盏灯,同时该程序带有一个输入源信号来输入究竟是那个灯点亮——显然定义一个枚举远远胜过用数字(1,2,3,4)表示具体某个灯亮好得多。因此枚举和数值往往是密不可分的。通常情况下枚举第一项默认是0,以后每项递增1;但是某些情况下(例如“多态枚举”——指一个枚举值可能包含多种枚举状态)的情况下,你完全为某些枚举指定对应的值,而且必须如此(理由后面说明)。譬如判断任意一个文件在Windows下的状态(假设3种):

[C#]

public enum FileAttributes
{
   Normal = 1
   Hidden = 1<<1
   ReadOnly = 1<<2
}

[VB.NET]

Public Enum FileAttributes
    Normal = 1
    Hidden = 1<<1
    [ReadOnly] = 1 << 2
End Enum

之所以要为每个枚举单独指定对应的数值,其原因在于一个文件不可能单独是“一种状态”(比如一个文本文件可能具备“隐藏”和“只读”双态),显然单独用一个枚举值根本无法表示,而且要把每种状态的组合列出也根本不可能;不过大家应该清楚一点——那就是枚举和数值之间的转换关系:

1)当把一个数字转换成枚举,且这个数字映射到某个特定的枚举值,则直接输出该枚举值。

2)当把一个数字转换成枚举,且这个数字无法映射到某个特定的枚举值,则直接输出该数字。

因此.net中允许枚举进行“与或非”的操作——其中“或”操作等同于“+”(这个枚举不支持),把不同的枚举映射的数值求和,那么所得到的结果自然也就是包含多个枚举值的结果。

这样求和有什么先决条件么?显然是有的。因为“或”运算是“全1得0,见1得1”(“全1”表示两个比特位都是1,那么得到0,例如二进制:1+1=0)。这样的话,如果枚举值是按照默认的“递增”的话,显然会造成数据上的混乱(譬如一开始0,第二项1,那么“或”变成1,以后你再也推断不出那个“0”对应的枚举值曾经用过;再譬如从2开始,第二项3,那么“或”的结果是5,“5”的二进制为“0000 0101",这样的话“2”和“3”其实也就无法得到了(因为“或”的缘故乱套了)。

要使的其“不乱套”,唯一的方法就是每个枚举值取“2”的N次方(理由很简单:因为2的N次方只有特定位为1,其余均为0,这样“或”不会导致“1变成0”的惨剧)。例如示例代码中每个枚举值都是前一次“左移一位”(本质是2的N次方!),这样“或”的结果是0000 0001+0000 0010=0000 0011(十进制3)。

对于我们而言,要判断某个“多态枚举”是否包含特有值,只需把这个值与“特定值”进行“与”操作(因为“与”是“见0得0,全1得1”,可以屏蔽其它位而保留特定位)。之前说过“2的N次方”只有特定位是1,那么“或”之后对其“与”,则只需判断特定位是否为1即可了。代码如下(假设FileAttributes是一个已经定义并且赋值的枚举变量)。

[C#]

if(FileAttributes & FileAttributes.Hidden == File.Attributes.Hidden)
{
   ………………
}

[VB.NET]

If (FileAttributes And FileAttributes.Hidden = FileAttributes.Hidden) Then
  ………………

End If


 同样地,Enum中有一个Parse(或者TryParse)方法允许我们把枚举名称(或者枚举名称对应的数值)转化成相应的枚举类型。这里如果输出多个枚举,自动做“或”运算:

下面可以做一个实验:

[C#]

enum Colors { None = 0, Red = 1, Green = 2, Blue = 3 };
string
[] colorStrings = { "Red,Green" }; foreach (string colorString in colorStrings) { Colors colorValue; if (Enum.TryParse(colorString, out colorValue)) Console.WriteLine(colorValue); }

[VB.NET]

Enum Colors
None = 0
Red = 1
Green = 2
Blue = 3
End Enum
Dim
colorStrings As String() = {"Red,Green"} For Each colorString As String In colorStrings Dim colorValue As Colors If [Enum].TryParse(colorString, colorValue) Then Console.WriteLine(colorValue) End If Next

如果直接输出“colorValue”,那么结果是“3”,恰恰是Red+Green的枚举值。(是“或”关系)。

记住:“枚举”和“数值”是一一对应的,否则就会出现“张冠李戴”的错误,啼笑皆非:

[C#]

public class Example
{
     enum Colors { None = 0, Red = 1, Green = 2, Blue = 3 };

   public static void Main()
   {
      string[] colorStrings = {  "Red,Green" };
      foreach (string colorString in colorStrings)
      {
         Colors colorValue;
         if (Enum.TryParse(colorString, out colorValue))        
            Console.WriteLine(colorValue);
      }
   }
}

[VB.NET]

Public Class Example
    Private Enum Colors
        None = 0
        Red = 1
        Green = 2
        Blue = 3
    End Enum

    Public Shared Sub Main()
        Dim colorStrings As String() = {"Red,Green"}
        For Each colorString As String In colorStrings
            Dim colorValue As Colors
            If [Enum].TryParse(colorString, colorValue) Then
                Console.WriteLine(colorValue)
            End If
        Next
    End Sub
End Class

"Red"+"Green"=3,因此最终输出的是Blue,因为Blue=3。

posted @ 2012-07-17 14:56  Serviceboy  阅读(1327)  评论(0编辑  收藏  举报