一些枚举是标志。也就是说,它可以具有枚举成员的任意组合并且仍然有效。
在FileAttributes
枚举的情况下,一个文件可以ReadOnly
同时Hidden
存在。同样,文件可以是Hidden
,ReadOnly
和System
. 为每个组合编写一个枚举成员将给出 16 个不同的成员!非常低效。
使用标志类型枚举时,检查值是否包含指定枚举成员的方法是以按位(二进制)方式将其与自身进行比较。
给定以下FileAttributes
枚举的简化定义:
[Serializable, Flags]
public enum FileAttributes
{
Archive = 32,
Hidden = 2,
Normal = 128,
ReadOnly = 1,
System = 4,
Temporary = 256
}
System
也被标记的文件ReadOnly
将具有值5
( 4 + 1
)。ReadOnly
尝试使用代码确定文件是否是
File.GetAttributes(fileName) == FileAttributes.System
将这样评估:
5 == 4
结果将是False
。
确定文件是否具有System
属性集的最佳方法是对文件的属性和要确定其存在的属性进行二进制 AND 运算。在代码中,你会这样写:
(File.GetAttributes(fileName) & FileAttributes.System) == FileAttributes.System
System
在进行比较之前,这会剥离除属性之外的所有其他属性。从数学上讲,它会这样评估:
0101(系统+隐藏)
AND 0100(系统)
------ -----
0100(系统)
然后将结果 ( 0100
) 与系统属性 ( 0100
) 进行比较,结果将是True
。
一方面,代码的(0x0101 & 0x0100) == 0x0100
计算结果为True
.
从 .NET 4.0 开始,Microsoft 已包含Enum.HasFlag
确定枚举值中是否存在标志的方法。因此,您不必自己键入所有代码。在处理具有该Flags
属性的 Enum 类型时,您可以简单地使用该HasFlag
方法来检查是否存在特定标志。因此,您的行将被写为
File.GetAttributes(fileName).HasFlag(FileAttributes.System)
波浪号 ( ~
) 标记在用于数值(或任何可以“退化”为int
、或的类型)时uint
,具有翻转数字位的效果,产生数字的补码(除指定的)。long
ulong
例如,给定 16 位数字 4 ( 0x0100
),它的补码 ( ~4
) 将是 11 ( 0x1011
)
0100 -> 1011
XOR
波浪号与对被比较类型的最大值执行相同的效果。对于 16 位数字,最大值为 15 ( 1111
),因此您的波浪号将计算为:
0100
异或 1111
--------
1011
因此,您的代码中的效果File.SetAttributes(fileName, File.GetAttributes(fileName) & ~FileAttributes.Archive)
将获取文件的属性,删除该Archive
属性,然后将其设置回文件。
假设文件的属性是 Archive + Hidden,它的值为 34 ( 0x00100010
),~Archive
值为0x11011111
.
评估将是这样的
(存档+隐藏)0x00100010
AND (~存档) 0x11011111
---------- ----------
隐藏 0x00000010
该文件的属性随后将更改为仅隐藏(存档属性将被删除)。