1

我最近在 stackoverflow 上得到了一些很大的帮助。其中一个答案让我有些困惑,由于评论框的限制,我觉得不适合得到解释。

请查看下面的代码。

if ((File.GetAttributes(fileName) & FileAttributes.Archive) == FileAttributes.Archive)
{
    // Archive file.
}

我的问题是你为什么要在 & 之后包含逻辑(见粗体)
(File.GetAttributes(fileName) & FileAttributes.Archive ) == 等

FileAttributes.Archive == FileAttributes.Archive 肯定会一直匹配吗?

有没有人对此有解释(IMO这可能是一个错字/错误,但我之前假设了太多事情,以后才会更正!)

第二个问题是波浪号~在这段代码中的作用:

File.SetAttributes(fileName, File.GetAttributes(fileName) & ~FileAttributes.Archive);
4

5 回答 5

5

一些枚举是标志。也就是说,它可以具有枚举成员的任意组合并且仍然有效。

FileAttributes枚举的情况下,一个文件可以ReadOnly同时Hidden存在。同样,文件可以是Hidden,ReadOnlySystem. 为每个组合编写一个枚举成员将给出 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,具有翻转数字位的效果,产生数字的补码(除指定的)。longulong

例如,给定 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

该文件的属性随后将更改为仅隐藏(存档属性将被删除)。

于 2012-10-23T11:34:00.397 回答
2

问题是FileAttributes具有Flags属性。表示所有值都可以组合(例如存档和隐藏)。

要确定是否真的设置了特定值,您必须屏蔽所有其他值。为此,该类中的HasFlag方法也Enum存在,可以在您的示例中使用如下:

if(File.GetAttributes(fileName).HasFlag(FileAttributes.Archive))
{
    // Archive file.
}

第二个示例确实从位掩码中删除了一个精确值。因此,它删除了归档属性而不触及掩码中的所有其他位(例如只读或隐藏)。对于此任务,枚举类中不存在任何方法。

于 2012-10-23T09:50:38.240 回答
2

File.GetAttributes 方法返回一个枚举,该枚举具有一个 Flags 属性,该属性允许其成员值的按位组合。换句话说,所有相关属性的所有位值都组合在一个整数对象中。'&' 或按位与运算符允许您提取对象的相关位。与原始属性的比较是为了清楚起见,简单地寻找非零值在逻辑上同样正确。

http://msdn.microsoft.com/en-us/library/system.io.fileattributes.aspx

于 2012-10-23T09:54:44.360 回答
1

这是一个所谓的蒙面比较。

(File.GetAttributes(fileName) & FileAttributes.Archive)
    return FileAttributes.Archive

如果属性中有 FileAttributes.Archive 并在任何其他情况下返回 false。

例子:

如果文件属性具有值:

hidden  archive readonly 
   1       1       0

按位和(File.GetAttributes(fileName) & FileAttributes.Archive)

返回

hidden  archive readonly 
   0       1       0

它是平等的FileAttributes.Archive

如果文件属性具有值:

hidden  archive readonly 
   1       0       1

按位和(File.GetAttributes(fileName) & FileAttributes.Archive)

返回

hidden  archive readonly 
   0       0       0
于 2012-10-23T09:51:16.337 回答
1

'~' 运算符是按位 NOT(补码)。请参见按位补码运算符

于 2012-10-23T09:57:14.900 回答