最近开发中遇到一些问题,我需要保存一系列的数据,我把保存的动作分开写成单独的方法,然后用一个总的方法来组合所有保存的动作。

伪代码如下:分别有三个已经封装好的方法,然后在SaveAll里面把这些方法组合起来。

void SaveAll()
{    
    // 保存表格数据
    SaveTableData();

    // 保存树形结构数据
    SaveTreeViewData();

    // 保存导入的信息
    SaveImportData();
}

本来我有一个保存按钮,确实是要所有数据都保存,调用这个方法确实没问题。但有些按钮,只想保存导入的数据就行,有些按钮需要同时保存表格和树形结构的数据,不需要保存导入的数据。

有一个思路就是在需要保存不同数据的地方,分别都调用各自保存的方法,但这样我觉得管理起来很麻烦,我就只想调用SaveAll这一个方法,给它传指定的参数,去保存对应的数据。

于是我定义了一个枚举

public enum SaveOption
{
    TableData,
    TreeViewData,
    ImportData,
}

SaveAll方法改造成

void SaveAll(SaveOption saveOpt)
{
    if (saveOpt == saveOpt.TableData)
        // 保存表格数据
        SaveTableData();
    if (saveOpt == saveOpt.TreeViewData)
        // 保存树形结构数据
        SaveTreeViewData();
    if (saveOpt == saveOpt.ImportData)
        // 保存导入的信息
        SaveImportData();
}

这样,我就可以只调用SaveAll分行,传不同的参数,就可以分别保存不同的数据了。

但这样的弊端就是,每次只能传一个参数,如果我想保存表格数据、树形数据,就需要调用两次方法,传两次不同的参数。

我就想着有没有什么办法,可以一次传多个参数。

这就是今天要提到的枚举位运算传参。

枚举位运算

需要对枚举类进行改造:

  • 一、 修改枚举类,变标记枚举
  1. 添加标记特性[Flags]`
  2. 把枚举值都设置成2的x次方,用1左移x位就是2的x次方。
1 << 1: 即1左移1位就是2的1次方,即2

1 << 2: 即1左移2位就是2的2次方,即4

[Flags]
public enum SaveOption
{
    TableData = 1 
    TreeViewData = 1 << 1,
    ImportData = 1 << 2
}
  • 二、传参时,使用按位或运算合并参数

比如我同时想保存表格数据,又想保存树形结构数据,调用方法时,传参的写法应如下:

SaveAll(SaveOption.TableData | SaveOption.TreeViewData);
  • 三、 解析传参结果

上面传了两个参数,那如何知道传了哪些参数?用按位与(&)进行逆运算即可

改造SaveAll方法如下

void SaveAll(SaveOption saveOpt)
{
    if ((saveOpt & SaveOption.TableData) == saveOpt.TableData)
        // 保存表格数据
        SaveTableData();
    if ((saveOpt & SaveOption.TreeViewData) == saveOpt.TreeViewData)
        // 保存树形结构数据
        SaveTreeViewData();
    if ((saveOpt & SaveOption.ImportData) == saveOpt.ImportData)
        // 保存导入的信息
        SaveImportData();
}

用传进来的参数按位与某个枚举,如果结果等于该枚举,说明传入的参数是中带有这个枚举值,从而执行对应的方法。

这就是实现了声明一个参数,但是可以传多个值,并且在方法内可以知道传入了哪些参数的效果了。

这样的写法,写起来比较简介。

比如我现在想保存表格数据和导入的数据。只需调用

SaveAll(SaveOption.TableData | SaveOption.ImportData);

这种写法就很灵活,复用性更强,管理也方便。

原理测试

上面是用C#的枚举来举例的,枚举的本质其实就是整数,只是有对应的名字而已,下面我用整数的代码来测试这个结果。

我有一些数字1、2、4、8、16。(注意,数值必须是2的n次方,不然按位与的结果会有重叠)

定义一个变量:i= 1 | 2;i的值是1按位或2。

然后用i分别按位与1、2、4、8、16,看结果

可以看到:i 按位与1、2的结果就是1、2本身,如果是按位与其它值,就是0。

用枚举位运算传参之后,判断传入的参数就是按这个原理。即用按位或传参,按位与逆运算回来。

具体的位运算结果,大家可以自行百度,有些是用按位或合并参数传参,有些是用按位左移传参,然后按位右移解析回来。