“多态枚举”数值如何判断?
枚举的作用就是用“字面量”的形式(附带智能提示)取代纯粹的数字化。假设某一个程序中有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。