位運算在角色許可權設計中的應用

来源:https://www.cnblogs.com/jdzhang/archive/2018/05/14/9034171.html
-Advertisement-
Play Games

1.引言 2.位運算基礎 3.位運算在角色許可權設計中的應用 4.為什麼in32的範圍是-2^31 ~ 2^31-1 ? 5.同餘的概念 6.模的概念幫助理解補數和補碼。 一、引言 這周在做一個新增角色許可權需求時,遇到下麵這樣一行代碼,這篇文章將圍繞這行代碼展開。 二、位運算基礎 關於位運算的基礎知識 ...


1.引言

2.位運算基礎

3.位運算在角色許可權設計中的應用

4.為什麼in32的範圍是-2^31 ~ 2^31-1 ?

5.同餘的概念

6.模的概念幫助理解補數和補碼。 

一、引言

這周在做一個新增角色許可權需求時,遇到下麵這樣一行代碼,這篇文章將圍繞這行代碼展開。

user.RoleType = ~(~user.RoleType | 511) | requestDTO.Role;

二、位運算基礎

關於位運算的基礎知識參見:

百度百科:https://baike.baidu.com/item/%E4%BD%8D%E8%BF%90%E7%AE%97

維基百科:https://zh.wikipedia.org/wiki/%E4%BD%8D%E6%93%8D%E4%BD%9C

總結如下:

1.位邏輯非運算(記憶技巧: 二進位按位取反) 位邏輯非運算按位對運算對象的值進行非運算,即:如果某一位等於0,就將其轉變為1;如果某一位等於1,就將其轉變為0。 比如,對二進位的10010001進行位邏輯非運算,結果等於01101110, 用十進位表示就是:~0111(十進位7)=1000(十進位8)   2.位邏輯與運算(記憶技巧: 二進位按位 true&&true=true才為true) 位邏輯與運算將兩個運算對象按位進行與運算。與運算的規則:1與1等於1,1與0等於0,0與0等於0。 比如:10010001(二進位)&11110000等於10010000(二進位)   3.位邏輯或運算(記憶技巧: 二進位按位 true||false=true,true||true=true) 位邏輯或運算將兩個運算對象按位進行或運算。或運算的規則是:1或1等1,1或0等於1, 0或0等於0。比如10010001(二進位)| 11110000(二進位)等於11110001(二進位)   4.位邏輯異或運算(記憶技巧: 二進位按位 true||false=true 不同時true) 位邏輯異或運算將兩個運算對象按位進行異或運算。異或運算的規則是:1異或1等於0, 1異或0等於1,0異或0等於0。即:相同得0,相異得1。 比如:10010001(二進位)^11110000(二進位)等於01100001(二進位)   5.位左移運算 位左移運算將整個數按位左移若幹位,左移後空出的部分0。比如:8位的byte型變數 byte a=0x65(即二進位的01100101),將其左移3位:a<<3的結果是0x27(即二進位的00101000)   6.位右移運算  位右移運算將整個數按位右移若幹位,右移後空出的部分填0。比如:8位的byte型變數 Byte a=0x65(既(二進位的01100101))將其右移3位:a>>3的結果是0x0c(二進位00001100)

 三、位運算在角色許可權設計中的應用(優缺點)

業務場景:有A.B.C.D四個基礎角色,現在需要新增一個複合角色(架構師),可以配置用戶。

下麵是一個demo例子,位運算在角色許可權中的應用

   [Flags]
    public enum RoleType
    {
        /// <summary>
        /// 無角色
        /// </summary>
        [Description("無角色")]
        None = 0,
        /// <summary>
        /// 普通用戶角色
        /// </summary>
        [Description("普通用戶")]
        A = 1,
        /// <summary>
        /// 初級開發
        /// </summary>
        [Description("初級開發")]
        B = 2,
        /// <summary>
        /// 中級開發
        /// </summary>
        [Description("中級開發")]
        C = 4,
        /// <summary>
        /// 高級開發
        /// </summary>
        [Description("高級開發")]
        D = 8,
        /// <summary>
        /// 架構師
        /// </summary>
        [Description("架構師")]
        E = 8
    }
    public class UnitTest1
    {
        public static void Test1()
        {
            var a = RoleType.A | RoleType.B;  //變數a為 A | B
            var b = RoleType.B | RoleType.D;  //變數b為 B | D
            var aa = a.ToString();//變數aa為 "A,B" 

            var bb = a & (~RoleType.A);//從組合狀態中去掉一個元素A ,結果為 枚舉 B
            var bb1 = ~(~a | RoleType.A); //bb結果等價於bb1
            var cc = (b & RoleType.B) != 0;//檢查組合狀態是否包含枚舉 B  

            var dd = RoleType.A | RoleType.B | RoleType.B | RoleType.B; //變數dd為 A | B
        }
    }

分析:

1.為什麼枚舉角色數都是2的倍數?

十進位  二進位

1    01

2    10

4    100

8    1000

。。。。。。

我們發現在各個位上值都是唯一的,所以做位或運算時,不同值的運算結果是唯一的;反過來,我們也可以根據結果值推算出來包含的枚舉(即業務中的角色)

ok,到這裡我們再看開頭引言中的那行代碼,可以寫為

user.RoleType = (user.RoleType & ~511) | requestDTO.Role;

抽象為x=(x&~y)|z,就是去除x中的y角色,再與z做位或組合。

想下,這個在保存用戶角色的時候會很巧妙,就是去除用戶 x(原有角色)中的 y(基礎角色),再和z(要保存的角色),做位或運算組合 得出一個新的要保存角色。

優點:一個roletype欄位可以保存用戶的所有角色信息

缺點:當已經有31個角色,當需要再新增角色的時候,就變的尷尬了(超出了int32位)

解決辦法

1.將roletype欄位擴展為64位,但在系統的後期迭代階段影響範圍頗大,還是存在用完的時候

2.新增一張表,將複合角色與基礎角色 這兩個拆分位兩個欄位,單獨保存兩者之間關係

四、為什麼in32的範圍是-2^31 ~ 2^31-1 ?

為什麼會介紹這個問題,因為當新增角色時,2^32超出了int32的範圍,但是為什麼int32範圍是-2^31 ~ 2^31-1 ?本著對刨根問底的態度,便追尋了下去。

我們可以先研究下8位二進位的標識範圍為什麼是-2^7~2^7-1

這裡要說下 原碼,反碼,補碼的概念。

原碼

正數的原碼就是它的本身

假設使用一個位元組存儲整數,整數10的原碼是:0000 1010

負數用最高位是1表示負數

假設使用一個位元組存儲整數,整數-10的原碼是:1000 1010

反碼

正數的反碼跟原碼一樣

假設使用一個位元組存儲整數,整數10的反碼是:0000 1010

負數的反碼是負數的原碼按位取反(0變1,1變0),符號位(首位)不變

假設使用一個位元組存儲整數,整數-10的反碼是:1111 0101

補碼

正數的補碼和原碼一樣

假設使用一個位元組存儲整數,整數10的補碼是:0000 1010(這一串是10這個整數在電腦中存儲形式)

負數的補碼是負數的反碼加1

假設使用一個位元組存儲整數,整數-10的補碼是:1111 0110(這一串是-10這個整數在電腦中存儲形式)

 

在電腦中,為什麼不用原碼和反碼,而是用補碼呢?

使用原碼計算10-10

         0000 1010  (10的原碼)

    +        1000 1010   (-10的原碼)

------------------------------------------------------------

         1001 0100  (結果為:-20,很顯然按照原碼計算答案是否定的。)

 

分析:正常的加法規則不適用於正數與負數的加法,因此必須制定兩套運算規則,一套用於正數加正數,還有一套用於正數加負數。從電路上說,就是必須為加法運算做兩種電路

 

使用反碼計算10-10

      0000 1010  (10的反碼)

    +   1111 0101  (-10的反碼)

------------------------------------------------------------

      1111 1111  (計算的結果為反碼,我們轉換為原碼的結果為:1000 0000,最終的結果為:-0,很顯然按照反碼計算答案也是否定的。)

使用補碼計算10-10

      0000 1010  (10的補碼)

   +   1111  0110  (-10的補碼)

------------------------------------------------------------

      1 0000 0000  (由於我們這裡使用了的1個位元組存儲,因此只能存儲8位,最高位(第九位)那個1沒有地方存,就被丟棄了。因此,結果為:0)

 

分析:補碼表示法可以將加法運算規則,擴展到整個整數集,從而用一套電路就可以實現全部整數的加法。補碼是電腦中存儲整數的形式。

 

八位二進位正數的補碼範圍是0000 0000 ~ 0111 1111 即0 ~ 127

負數的補碼範圍是正數的原碼0000 0000 ~ 0111 1111 取反加一(也可以理解為負數1000 0000 ~ 1111 1111化為反碼末尾再加一)。 所以得到 1 0000 0000 ~ 1000 0001

1000 0001作為補碼,其反碼是1000 0000,其原碼是1111 1111(-127)

依次往前推,可得到1111 1111作為補碼,其反碼1111 1110,原碼1000 0001(-1)

那麼補碼0000 0000(1被捨去)的原碼是1000 0000符號位同時也可以看做數字位即表示-128(-2^7)

類推:in32的範圍便是-2^31 ~ 2^31-1 

 五、同餘的概念

兩個整數a,b,若它們除以整數m所得的餘數相等,則稱a,b對於模m同餘

記作 a ≡ b (mod m)

讀作 a 與 b 關於模 m 同餘。

六、模的概念

時間不早了,模的概念可以幫助理解補數和補碼,下篇博客中提到吧。。。

 

博主的文章沒有高度、深度和廣度,只是湊字數。由於博主的水平不高(其實是個菜B),不足和錯誤之處在所難免,希望大家能夠批評指出。

博主是利用讀書、參考、引用、抄襲、複製和粘貼等多種方式寫的文章,請原諒博主成為一個無恥的文檔搬運工!

參考:

https://www.cnblogs.com/yinzhengjie/p/8666354.html

https://blog.csdn.net/fenzang/article/details/53500852?utm_source=itdadao&utm_medium=referral

http://www.ruanyifeng.com/blog/2009/08/twos_complement.html

http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html#!comments


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 手冊里可能有寫,但不是特別清晰,在這給個實例,有兩種方式: 1.多個入口文件: 將public下的index.php複製一份,粘貼、重命名為對應模塊的名字,如admin: 編輯admin.php的內容,修改模塊綁定的代碼: 之後訪問方式就是'功能變數名稱/admin.php',沒有映射功能變數名稱就是'localh ...
  • 一. Java多線程: Java給多線程編程提供了內置的支持。一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。 多線程是多任務的一種特別的形式,但多線程使用了更小的資源開銷。 這裡定義和線程相關的另一個術語--進程:一個進程包括由操作系統分配的記憶體空 ...
  • jenkins中集成commander應用 jenkins 集成測試 promotion 公司的應用較多,所以需要瞭解這幾種應用在jenkins中如何做構建,我自己參與的有兩種commander的應用,一種是大數據類的,一個是我們服務端架構組的scala應用 1、大數據應用BigData 配置如下: ...
  • 1、說一說Servlet的生命周期? Servlet有良好的生存期的定義,包括載入和實例化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet介面的init(),service()和destroy方法表達。 Servlet被伺服器實例化後,容器運行其init方法,請 ...
  • "回到 DirectX11 使用Windows SDK來進行開發" "DirectX Tool Kit下載" DirectX Tool Kit是一個包含許多類的集合,用於為公共Windows平臺編寫Direct3D 11 C++代碼。裡面包含如下可用的頭文件(基本上都在名稱空間DirectX中): ...
  • 瞭解 "structc https://github.com/wangzhione/structc" structc 是 C 構建基礎項目框架. 不是太驚艷, 但絕對是 C 簡單項目中一股清流. 它的前身是 simplec 框架. "simplec https://github.com/wangzh ...
  • STM32F103C8T6工程模板 https://pan.baidu.com/s/1jAgJQCUmFg7NtpX5bOkCWQ STM32F103ZET6工程模板 ...
  • lASP.NET MVC系列文章 【01】淺談Google Chrome瀏覽器(理論篇) 【02】淺談Google Chrome瀏覽器(操作篇)(上) 【03】淺談Google Chrome瀏覽器(操作篇)(下) 【04】淺談ASP.NET框架 【05】淺談ASP.NET MVC運行過程 【06】淺 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...