问题出发点http://topic.csdn.net/u/20100404/11/fa54404c-1510-4027-a799-1bc420c53444.html?14163
原文: enum TU
{
A=0x01,
B=0x04,
C=0x05,
D=0x15,
E=0x0
}TU t=TU.D;
t-=TU.A;//这是对的
t+=TU.A//错误
t=t+TU.A//错误
t=t-TU.A//错误-----------------------------------------
1.-=在枚举中的意义
二元 - 运算符是为所有数值类型和枚举类型预定义的,其功能是从第一个操作数中减去第二个操作数。
猜想:从整体上来看在此处t -= TU.A的应该是移除效果.
为什么会猜想是移除,原因要从enum的[FlagsAttribute]说起.
enum按位运算很常用,例如: FileAttributes.ReadOnly | FileAttributes.Hidden;
说到enum的按位运算,当定义的enum元素用 2 的幂(即 1、2、4、8 等)定义枚举常量。这意味着组合的枚举常量中的各个标志都不重叠.在使用ToString()时,才能枚举出所有的元素值.有以下例子:using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
TU t = TU.One| TU.Two | TU.Four;
Console.WriteLine(((Int32)t).ToString());
Console.WriteLine(t.ToString());
t -= TU.One;//从t中移除TU.One
Console.WriteLine(((Int32)t).ToString());
Console.WriteLine(t.ToString());
}
}
[FlagsAttribute]
enum TU
{
One = 1,
Two = 2,
Four = 4,
Eight = 8,
Sixteen =16
}
}运行结果
7
One,Two,Four
6
Two,Four
2.为什么不提供+=
a.从意义上来说+=和|=的作用相当.所以不必提供该操作.
b.实际上个人觉得+=(|=)比-=更容易产生不可预知的问题.例如FileAttributes.Normal和 FileAttributes.Hidden;FileAttributes.Normal标识文件未设置任何属性,FileAttributes.Hidden则是标识文件是隐藏的,两者相异.这其中有一些微妙的地方,下文将说到.3.enum的微妙之处
以下引自MSDN中<<对FlagsAttribute 和 Enum 的准则>>的第二条.
用 2 的幂(即 1、2、4、8 等)定义枚举常量。这意味着组合的枚举常量中的各个标志都不重叠。
enum在实际应用中会有类似FileAttributes.Normal的情况.例如存在一个自定义的文件操作枚举FileOperations,假设该枚举存在一个值None ,该值是用于标识未指定其他值的情况.
该enum如下. [FlagsAttribute]
enum FileOperations
{
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
None = 16
}然后进行以下实验using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
FileOperations f = FileOperations.Delete | FileOperations.Read;
Console.WriteLine("原始的值\r\n" + f.ToString());
f -= FileOperations.Delete;
Console.WriteLine("移除Delete后的值\r\n"+f.ToString());
f -= FileOperations.Read;
Console.WriteLine("移除Read后的值\r\n" + f.ToString());
} [FlagsAttribute]
enum FileOperations
{
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
None = 16,
}
}
}运行结果:
原始的值
Read,Delete
移除Delete后的值
Read
移除Read后的值
0
请按任意键继续. . .
这里我们可以看到,FileOperations f = FileOperations.Delete | FileOperations.Read依次移除后,状态应该是前面提到的该值是用于标识未指定其他值的情况.,即None,但实际上f并没得到我们想要的值.
然后我们将代码加经改进using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
FileOperations f = FileOperations.Delete | FileOperations.Read;
Console.WriteLine("原始的值\r\n" + f.ToString());
f -= FileOperations.Delete;
Console.WriteLine("移除Delete后的值\r\n"+f.ToString());
f -= FileOperations.Read;
Console.WriteLine("移除Read后的值\r\n" + f.ToString());
} [FlagsAttribute]
enum FileOperations
{
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
None = 0,//这里是主要变化
}
}
}主要的变化是我们将None的值由16变成了0,运行结果如下:
原始的值
Read,Delete
移除Delete后的值
Read
移除Read后的值
None
请按任意键继续. . .
这样就达到了我们的目的.
假设我们需要扩展一个包含所有操作的值All,加以改进就行.using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
FileOperations f = FileOperations.Delete | FileOperations.Read | FileOperations.Write | FileOperations.Hidden;
Console.WriteLine("原始的值\r\n" + f.ToString());
f -= FileOperations.Delete;
Console.WriteLine("移除Delete后的值\r\n"+f.ToString());
f -= FileOperations.Read;
Console.WriteLine("移除Read后的值\r\n" + f.ToString());
f -= FileOperations.Write;
Console.WriteLine("移除Write后的值\r\n" + f.ToString());
f -= FileOperations.Hidden;
Console.WriteLine("移除Hidden后的值\r\n" + f.ToString());
} [FlagsAttribute]
enum FileOperations
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
All = 15//此处是关键
}
}
}运行结果:
原始的值
All
移除Delete后的值
Read, Write, Hidden
移除Read后的值
Write, Hidden
移除Write后的值
Hidden
移除Hidden后的值
None
注意上面的All不再是2的次幂.此前的None也不再是.All为前面所有值的和.None则为0;
这样的指定并没有破坏enum的位运算.
建义使用2的次幂做值的原因是因为1,2,4,8……2^n可以组合成任何1~2^n之间的数.如3=1+2,5=4+1,7=4+2+1……。
这样在做逻辑运算产生新值的时候会与原定义值重复。
而0和2^n+1不在此列。但微软似乎出于别的原因考虑,不推荐这样使用。FileAttributes 枚举使用的值是128。
4。意外的结果using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
FileOperations f = FileOperations.Hidden;
Console.WriteLine("原始的值\r\n" + f.ToString());
f -= FileOperations.Delete;
Console.WriteLine("移除Delete后的值\r\n"+f.ToString());
} [FlagsAttribute]
enum FileOperations
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
All = 15
}
}
}
虽然应用中不会从一个只包含Hidden的enum中减去一个Delete。,但这个结果着实让我吓一跳。上例从一个enum实例中移除一个值。原本f= Hidden;但移除Delete后,居然变成Delete了,因为8 - 4 = 4;
如果-=是移除的话,理论应该是None。-=是什么操作已经不重要了,不管它是什么,都带来了意料之中、情理之外的结果。
-=真的需要要达到一个移除操作的话。只需将要运算的变量进行一次|=运算,再执行-=即可。
原文: enum TU
{
A=0x01,
B=0x04,
C=0x05,
D=0x15,
E=0x0
}TU t=TU.D;
t-=TU.A;//这是对的
t+=TU.A//错误
t=t+TU.A//错误
t=t-TU.A//错误-----------------------------------------
1.-=在枚举中的意义
二元 - 运算符是为所有数值类型和枚举类型预定义的,其功能是从第一个操作数中减去第二个操作数。
猜想:从整体上来看在此处t -= TU.A的应该是移除效果.
为什么会猜想是移除,原因要从enum的[FlagsAttribute]说起.
enum按位运算很常用,例如: FileAttributes.ReadOnly | FileAttributes.Hidden;
说到enum的按位运算,当定义的enum元素用 2 的幂(即 1、2、4、8 等)定义枚举常量。这意味着组合的枚举常量中的各个标志都不重叠.在使用ToString()时,才能枚举出所有的元素值.有以下例子:using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
TU t = TU.One| TU.Two | TU.Four;
Console.WriteLine(((Int32)t).ToString());
Console.WriteLine(t.ToString());
t -= TU.One;//从t中移除TU.One
Console.WriteLine(((Int32)t).ToString());
Console.WriteLine(t.ToString());
}
}
[FlagsAttribute]
enum TU
{
One = 1,
Two = 2,
Four = 4,
Eight = 8,
Sixteen =16
}
}运行结果
7
One,Two,Four
6
Two,Four
2.为什么不提供+=
a.从意义上来说+=和|=的作用相当.所以不必提供该操作.
b.实际上个人觉得+=(|=)比-=更容易产生不可预知的问题.例如FileAttributes.Normal和 FileAttributes.Hidden;FileAttributes.Normal标识文件未设置任何属性,FileAttributes.Hidden则是标识文件是隐藏的,两者相异.这其中有一些微妙的地方,下文将说到.3.enum的微妙之处
以下引自MSDN中<<对FlagsAttribute 和 Enum 的准则>>的第二条.
用 2 的幂(即 1、2、4、8 等)定义枚举常量。这意味着组合的枚举常量中的各个标志都不重叠。
enum在实际应用中会有类似FileAttributes.Normal的情况.例如存在一个自定义的文件操作枚举FileOperations,假设该枚举存在一个值None ,该值是用于标识未指定其他值的情况.
该enum如下. [FlagsAttribute]
enum FileOperations
{
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
None = 16
}然后进行以下实验using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
FileOperations f = FileOperations.Delete | FileOperations.Read;
Console.WriteLine("原始的值\r\n" + f.ToString());
f -= FileOperations.Delete;
Console.WriteLine("移除Delete后的值\r\n"+f.ToString());
f -= FileOperations.Read;
Console.WriteLine("移除Read后的值\r\n" + f.ToString());
} [FlagsAttribute]
enum FileOperations
{
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
None = 16,
}
}
}运行结果:
原始的值
Read,Delete
移除Delete后的值
Read
移除Read后的值
0
请按任意键继续. . .
这里我们可以看到,FileOperations f = FileOperations.Delete | FileOperations.Read依次移除后,状态应该是前面提到的该值是用于标识未指定其他值的情况.,即None,但实际上f并没得到我们想要的值.
然后我们将代码加经改进using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
FileOperations f = FileOperations.Delete | FileOperations.Read;
Console.WriteLine("原始的值\r\n" + f.ToString());
f -= FileOperations.Delete;
Console.WriteLine("移除Delete后的值\r\n"+f.ToString());
f -= FileOperations.Read;
Console.WriteLine("移除Read后的值\r\n" + f.ToString());
} [FlagsAttribute]
enum FileOperations
{
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
None = 0,//这里是主要变化
}
}
}主要的变化是我们将None的值由16变成了0,运行结果如下:
原始的值
Read,Delete
移除Delete后的值
Read
移除Read后的值
None
请按任意键继续. . .
这样就达到了我们的目的.
假设我们需要扩展一个包含所有操作的值All,加以改进就行.using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
FileOperations f = FileOperations.Delete | FileOperations.Read | FileOperations.Write | FileOperations.Hidden;
Console.WriteLine("原始的值\r\n" + f.ToString());
f -= FileOperations.Delete;
Console.WriteLine("移除Delete后的值\r\n"+f.ToString());
f -= FileOperations.Read;
Console.WriteLine("移除Read后的值\r\n" + f.ToString());
f -= FileOperations.Write;
Console.WriteLine("移除Write后的值\r\n" + f.ToString());
f -= FileOperations.Hidden;
Console.WriteLine("移除Hidden后的值\r\n" + f.ToString());
} [FlagsAttribute]
enum FileOperations
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
All = 15//此处是关键
}
}
}运行结果:
原始的值
All
移除Delete后的值
Read, Write, Hidden
移除Read后的值
Write, Hidden
移除Write后的值
Hidden
移除Hidden后的值
None
注意上面的All不再是2的次幂.此前的None也不再是.All为前面所有值的和.None则为0;
这样的指定并没有破坏enum的位运算.
建义使用2的次幂做值的原因是因为1,2,4,8……2^n可以组合成任何1~2^n之间的数.如3=1+2,5=4+1,7=4+2+1……。
这样在做逻辑运算产生新值的时候会与原定义值重复。
而0和2^n+1不在此列。但微软似乎出于别的原因考虑,不推荐这样使用。FileAttributes 枚举使用的值是128。
4。意外的结果using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
FileOperations f = FileOperations.Hidden;
Console.WriteLine("原始的值\r\n" + f.ToString());
f -= FileOperations.Delete;
Console.WriteLine("移除Delete后的值\r\n"+f.ToString());
} [FlagsAttribute]
enum FileOperations
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
All = 15
}
}
}
虽然应用中不会从一个只包含Hidden的enum中减去一个Delete。,但这个结果着实让我吓一跳。上例从一个enum实例中移除一个值。原本f= Hidden;但移除Delete后,居然变成Delete了,因为8 - 4 = 4;
如果-=是移除的话,理论应该是None。-=是什么操作已经不重要了,不管它是什么,都带来了意料之中、情理之外的结果。
-=真的需要要达到一个移除操作的话。只需将要运算的变量进行一次|=运算,再执行-=即可。
解决方案 »
- process执行exe进行ftp传输的问题
- 做一个打字软件,第一行输完之后调到第二行
- .cs 里怎么给ascx里的控件设置选中项
- 在线等候高手解决
- 水晶报表动态改变纸张时,总是出现以下错误“设置打印机发生错误,错误信息为:无效索引。 (异常来自 HRESULT:0x8002000B (DISP_E_BADINDEX))”
- 求一WINFORM 的分页实例,最好的用控件完成的
- c#里面有没有向java中的log4j的东西啊?
- 面试题找不到答案?请指教一下: 关于自定义实现list<t>
- 用C#写.NET时 数据库出现问题???程序在里面(我就是想把数据放入数据库在读出来而已)
- 如何把窗口放入屏幕右下方显示时钟的那个框内?
- [to->ALL] __ 问题bat的问题 __
- winform ReportViewer 的打印布局
TU t = TU.D;
t -= TU.A;
t += (int)TU.A;
t = t + (int)TU.A;
t = t - (int)TU.A; 或者你重载一下+,-运算
这样使用枚举更多是臆断的吧。比较常见的写法是 enum FileOperations
{
Read = 1,
Write,
Delete,
Hidden,
None
}
t -= TU.A; // 按我的理解,这应该是等价于 t = (TU)(t - TU.A);
t -= TU.A; // 可以
t = (TU)(t - TU.A); // 可以,等价于上行
t = t - TU.A; // 错误
// 类比:byte b = 78;
b -= 5; // 可以
b = (byte)(b - 5); // 可以,等价于上行
b = b - 5; // 错误
两个枚举变量相加就没有明显的、自然的意义了,所以不允许。正如两个 DateTime 型的变量相减的意思是时间间隔,结果是 TimeSpan 型的变量,
而两个 DateTime 型的变量相加没有意义,不允许。
两个枚举变量相加就没有明显的、自然的意义了,所以不允许。正如两个 DateTime 型的变量相减的意思是时间间隔,结果是 TimeSpan 型的变量,
而两个 DateTime 型的变量相加没有意义,不允许。
楼主的长篇大论的核心就是想说明枚举量的 -= 操作应该是移除效果。但从5、6、8楼的分析来看,两个枚举量相减的意义是它们的间隔,结果是 int 型的,再把它强制转换为枚举量,已经失去了意义(正因为把这个 int 量转换为枚举量没有实际的意义,微软在此处才不允许隐式转换,而需要强制转换:t = (TU)(t - TU.A);)。x -= y; 只不过是 x = x - y; 的便捷写法罢了。
我们就以 LZ 的 FileOperations 枚举为例,两个枚举量相减(a - b)的结果是 int,而不是枚举量,尽管相减的结果可以找到匹配(结果是 4,与 Delete 匹配)。using System;[Flags]
enum FileOperations
{
Delete = 4,
Hidden = 8,
}class Program
{
static void Main()
{
FileOperations a = FileOperations.Hidden;
FileOperations b = FileOperations.Delete; object x = a - b; // 以下可以看出:结果是 int,而不是枚举。
Console.WriteLine(x); // 输出 4
Console.WriteLine(x.GetType()); // 输出 System.Int32
Console.WriteLine((FileOperations)x); // 输出 Delete
}
}
并且不是总是有效的,楼下说明。using System;[Flags]
enum FileOperations
{
Delete = 4,
Hidden = 8,
}class Program
{
static void Main()
{
FileOperations a, b = FileOperations.Delete;
// 想从 a 中移除 b,正确的做法如下:
a = FileOperations.Hidden;
a &= ~b; // 不论 a 是否含有 b,都可以得到正确的结果
Console.WriteLine(a); // 输出 Hideden,正确。 // 想从 a 中移除 b,不正确的做法如下:
a = FileOperations.Hidden;
a -= b; // 如果 a 不含有 b,就不能得到正确的结果
Console.WriteLine(a); // 输出 Delete,错误。 // 想从 a 中移除 b,另一种做法:
a = FileOperations.Hidden;
if (( a & b) == b) a -= b; // 先判断 a 是否含有 b,再相减,可以。
Console.WriteLine(a); // 输出 Hideden,正确。
}
}
enum FileOperations
{
Read = 1,
Write = 2,
Delete = 4,
Hidden = 8,
}class Program
{
static void Main()
{
FileOperations a, b = FileOperations.Delete | FileOperations.Read;
// 想从 a 中移除 b,正确的做法如下:
a = FileOperations.Hidden | FileOperations.Delete;
a &= ~b; // 不论 a 是否部分含有 b,都正确。
Console.WriteLine(a); // 输出 Hideden,正确。 // 想从 a 中移除 b,不正确的做法如下:
a = FileOperations.Hidden | FileOperations.Delete;
a -= b; // 如果 a 含有部分的 b,结果不知所云。
Console.WriteLine(a); // 输出 Read, Write, Delete,错误。 // 想从 a 中移除 b,另一种做法(错误):
a = FileOperations.Hidden | FileOperations.Delete;
if (( a & b) == b) a -= b; // 先判断 a 是否完全含有 b,再相减。
Console.WriteLine(a); // 输出 Delete, Hidden,错误。
// 想从 a 中移除 b,还一种做法(也不正确):
a = FileOperations.Hidden | FileOperations.Delete;
if (( a & b) != 0) a -= b; // 先判断 a 是否部分含有 b,再相减。
Console.WriteLine(a); // 输出 Read, Write, Delete,也不正确。
}
}
再转换为枚举没有什么实际意义,只是在某些特定的情况下表现为移除的效果。
所以 a -= b; 是不好的写法,因为把枚举量的间隔转换为枚举在很多情况下没意义。移除的正确而简单的写法是:a &= ~b;
但 a -= b; 只不过是 a = (a的类型)(a - b); 的简便写法而已,把一个 int 型的量(枚举量的间隔)转换为枚举量,在很多情况下没意义。