简简单单学会C#位运算
作者:梦在旅途 发布时间:[ 2016/7/14 10:40:56 ] 推荐标签:测试开发技术 .NET 位运算
四、寻找规律
我们先看一下10进制及2进制0~20的数字
10进制数:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
2进制数:00000,00001,00010,00011,00100,00101,00110,00111,01000,01001,01010,01011,01100,01101,01110,01111,10000,10001,10010,10011,10100
从2进制数0~20中,我们发现只要是2的偶数次方时,则位数发生变化,且多位中只有一个为1,其余位均为0,找出的数字如下:
00000、00001、00010、,00100、01000、10000
对应10进制数:0、1、2、4、8、16
如果对这些数全部进行位或运算,则终的结果是:11111,即5位会部是1
从这里发现了什么呢?我是看出来了,不知道各位看官是否看出规律,其实很简单,如果我们把每一位都当成一个控制开关或者说是存在不存在,那么0表示关或者不存在,1表示开或者存在,那么我们可以针对这个规律实现复杂的组合控制。
其实微软早应用了这个规律特性,比如:
typeof(Program).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
BindingFlags定义如下:
如上,每一个枚举项都是2的次方,每一项都是上一项的2倍,我们也可以利用这个规律实现类似的处理。
五、实现组合控制
Console.WriteLine("示例四:");
ButtonStyle userbtnStyle = ButtonStyle.OK | ButtonStyle.Cancel | ButtonStyle.Alert | ButtonStyle.Info;//用户需要显示的ButtonStyle,通过或运算组合在一起,得出2进制值:1111
string buttonStyleStr = null;
//进行位逻辑判断,能够准确识别userbtnStyle的组合的内容
if ((userbtnStyle & ButtonStyle.AlertInfo) == ButtonStyle.AlertInfo)
{
buttonStyleStr += "+" + Enum.GetName(typeof(ButtonStyle), ButtonStyle.AlertInfo);
}
else if ((userbtnStyle & ButtonStyle.Alert) == ButtonStyle.Alert)
{
buttonStyleStr += "+" + Enum.GetName(typeof(ButtonStyle), ButtonStyle.Alert);
}
else if ((userbtnStyle & ButtonStyle.Info) == ButtonStyle.Info)
{
buttonStyleStr += "+" + Enum.GetName(typeof(ButtonStyle), ButtonStyle.Info);
}
if ((userbtnStyle & ButtonStyle.OKCancel) == ButtonStyle.OKCancel)
{
buttonStyleStr += "+" + Enum.GetName(typeof(ButtonStyle), ButtonStyle.OKCancel);
}
else if ((userbtnStyle & ButtonStyle.OK) == ButtonStyle.OK)
{
buttonStyleStr += "+" + Enum.GetName(typeof(ButtonStyle), ButtonStyle.OK);
}
else if ((userbtnStyle & ButtonStyle.Cancel) == ButtonStyle.Cancel)
{
buttonStyleStr += "+" + Enum.GetName(typeof(ButtonStyle), ButtonStyle.Cancel);
}
Console.WriteLine("需要显示的按钮有:" + buttonStyleStr.Substring(1));
enum ButtonStyle
{
None = 0x00,
OK = 0x01,
Cancel = 0x02,
Alert = 0x04,
Info = 0x08,
OKCancel = 0x01 | 0x02,
AlertInfo = 0x04 | 0x08
}
输出结果:
需要显示的按钮有:AlertInfo+OKCancel
如果改变userbtnStyle的组合,得到的结果也会不同
另外一个示例:
Console.WriteLine("示例五:");
AllowType userPermission = AllowType.Add | AllowType.Update | AllowType.Upload | AllowType.Download | AllowType.Select;
string userPermissionStr = null;
if ((userPermission & AllowType.Edit) == AllowType.Edit)
{
userPermissionStr += "+" + Enum.GetName(typeof(AllowType), AllowType.Edit);
}
else
{
if ((userPermission & AllowType.Add) == AllowType.Add)
{
userPermissionStr += "+" + Enum.GetName(typeof(AllowType), AllowType.Add);
}
if ((userPermission & AllowType.Update) == AllowType.Update)
{
userPermissionStr += "+" + Enum.GetName(typeof(AllowType), AllowType.Update);
}
if ((userPermission & AllowType.Delete) == AllowType.Delete)
{
userPermissionStr += "+" + Enum.GetName(typeof(AllowType), AllowType.Delete);
}
if ((userPermission & AllowType.Upload) == AllowType.Upload)
{
userPermissionStr += "+" + Enum.GetName(typeof(AllowType), AllowType.Upload);
}
}
if ((userPermission & AllowType.Read) == AllowType.Read)
{
userPermissionStr += "+" + Enum.GetName(typeof(AllowType), AllowType.Read);
}
else
{
if ((userPermission & AllowType.Select) == AllowType.Select)
{
userPermissionStr += "+" + Enum.GetName(typeof(AllowType), AllowType.Select);
}
if ((userPermission & AllowType.Download) == AllowType.Download)
{
userPermissionStr += "+" + Enum.GetName(typeof(AllowType), AllowType.Download);
}
}
Console.WriteLine("用户具备的权限有:" + userPermissionStr.Substring(1));
enum AllowType
{
None = 0,
Add = 1,
Update = 2,
Delete = 4,
Select = 8,
Upload = 16,
Download = 32,
Edit = Add | Update | Delete | Upload,
Read = Select | Download
}
输出结果:
用户具备的权限有:Add+Update+Upload+Read
如果改变userPermission的组合,得到的结果也会不同
上述两个例子,是允分利用位或位与运算,大家可以理解位或是将两者拼在一起,位与是找出组合中是否有包含的部份
六、了解其它位运算
Console.WriteLine("示例六:");
int x1 = 108;
Console.Write("~位非运算:{0} -->> {1} ; {2} -->> {3}
",
Convert.ToString(x1, 10), Convert.ToString(~x1, 10),
Convert.ToString(x1, 2), Convert.ToString(~x1, 2));
Console.Write("<<位左移(移5位)运算:{0} -->> {1} ; {2} -->> {3}
",//说白了讲:左移N位是将二进制数后面补N位0
Convert.ToString(x1, 10), Convert.ToString(x1 << 5, 10),
Convert.ToString(x1, 2), Convert.ToString(x1 << 5, 2));
Console.Write(">>位右移(移5位)运算:{0} -->> {1} ; {2} -->> {3}
",//说白了讲:右移N位是将二进制数后面删除N位数(不论0或1)
Convert.ToString(x1, 10), Convert.ToString(x1 >> 5, 10),
Convert.ToString(x1, 2), Convert.ToString(x1 >> 5, 2));
Console.Write("^位异或(异或5)运算:{0} ^ {1} -->> {2} ; {3} ^ {4}-->> {5}
",
Convert.ToString(x1, 10),Convert.ToString(5, 10), Convert.ToString(x1 ^ 5, 10),
Convert.ToString(x1, 2), Convert.ToString(5, 2), Convert.ToString(x1 ^ 5, 2));
输出结果:
~位非运算:108 -->> -109 ; 1101100 -->> 11111111111111111111111110010011
<<位左移(移5位)运算:108 -->> 3456 ; 1101100 -->> 110110000000
>>位右移(移5位)运算:108 -->> 3 ; 1101100 -->> 11
^位异或(异或5)运算:108 ^ 5 -->> 105 ; 1101100 ^ 101-->> 1101001
~非运算:是一个单项运算符,用来对一个二进制按位取反,即将 0 变 1,1变 0。
<<左移:用来对一个数每个二进位全部左移若干位,说白了讲:左移N位是将二进制数后面补N位0
>>右移:用来对一个数每个二进位全部右移若干位,移到右端的低位被舍弃,对无符号数,高位补 0,说白了讲:右移N位是将二进制数后面删除N位数(不论0或1)
^异或运算: 也称 XOR 运算符。它的规则是若参加运算的两个二进位同号,则结果为0,异号则为1。即 0^0=0; 0^1=1; 1^0=1;1^1=0;说白了讲:若两个都为0,则为0,否则相同的则为0,不相同的则为1
小技巧说明:
大家在定义枚举时,除了0,1外,其余项只需要确保每一项乘以2得出下一项的值即可,如10进制数的值:0,1,2,4,8,16,32,64,128,256,16进制数的值:0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
通过10进制数的值与16进制数的值的对比发现,采用16进制定义枚举值更好,因为我们可以很快速的定义出我们需要的值(都是按照:0,1,2,4,8循环,只是位数上升而矣),比如:
0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x100,0x200,0x400,0x800,0x1000
对应的10进制数:0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096
明显16进制定义值相对简单一些,我们无需进行*2的计算,当然大家随意选择。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11