【5min+】 這些C#的運算符您都認識嗎?

作者:句幽

來源:https://www.cnblogs.com/uoyo/p/12307959.html

系列介紹

【五分鐘的dotnet】是一個利用您的碎片化時間來學習和豐富.net知識的博文系列。它所包含了.net體系中可能會涉及到的方方面面,比如C#的小細節,AspnetCore,微服務中的.net知識等等。
5min+不是超過5分鐘的意思,"+"是知識的增加。so,它是讓您花費5分鐘以下的時間來提升您的知識儲備量。

開篇廢話

這次更新好像隔的有點太久了。剛纔在園子裏看了一下我發的最後一篇文章,好吧,還停留在2020/01/24。本來計劃春節停更一個星期的,結果Get到了一個有史以來最長的春節????。

正文

對於“ + ”,“ - ”,“ * ”,“ / ”,“ is ”,“ as ” 等C#的運算符可能大家都再熟悉不過了。但是有時候大家在閱讀一些網站上的代碼或者開源項目的源碼時,會遇到一些奇奇怪怪的運算符,特別當幾個少見的運算符連在一起的時候,彷彿有一種 “別人的C#和我的C#怎麼不一樣” 的感覺。

隨着C#的版本更新,它爲我們提供了許許多多的語法糖和新運算符方便我們更流暢的來編寫代碼。當有時候遇到不認識的運算符,就會本着 “百度不行就谷歌” 的程序員大法來瘋狂操作一波。但是!! 搜索引擎他喵的居然不認這些符號。

所以,本文就整理了一些好玩兒的運算符做成了一個合集。如果碰到了不認識的操作符,也方便在這兒來查找。

先來看一段代碼吧:

複製代碼

if (isFlagged)
{
    _bits[propertyIndex / BitsPerInt] |= 1 << (propertyIndex % BitsPerInt);
}
else
{
    _bits[propertyIndex / BitsPerInt] &= ~(1 << (propertyIndex % BitsPerInt));
}
//節選自EF Core 中的結構體 “StateData”

有沒有猛的一看感覺已經不認識了的樣子????。畢竟對於咱們平時開發應用層面的開發者來說,很多位運算符很少用到,一下碰到了都忘記了什麼意思。

各類運算符

補位運算符 ~

~ 運算符通過反轉每個位產生其操作數的按位求補:

複製代碼

byte a = 10;   // 二進制 0000 1010
var b = (byte)~a;    // 二進制 1111 0101 。 b的十進制:245

移位運算符 << 和 >>

<< 運算符將其左側操作數向左移動:

複製代碼

byte a = 10;   // 0000 1010
var b = (byte)a<<2;    // 0010 1000。  b=40

>> 運算符將其左側操作數向右移動

複製代碼

byte a = 10;   // 0000 1010
var b = (byte)a<<2;    // 0000 0010。  b=2

比如 10 * 2^3 當我們用C#寫的時候可能會寫: 10 * Math.Pow(2,3) ,而現在可以直接寫 10 << 3。

邏輯運算符 ^

當然邏輯運算符還有其它的幾個,比如 & 和 | ,這些平時大家用的比較多所以就不多寫了。

^ 運算符計算其操作數的位邏輯異或:

複製代碼

byte a = 10;   // 0000 1010
var b = a ^ 0b_0010_1011;    // 0010 0001

所以如果配上咱們C#的複合運算,比如 += , -=。相應的,上面的符號就可以寫成 >>= ,|= , &= , ^= 等。

複製代碼

byte a = 10;
a <<=2;   // 40

索引運算符 ^

沒錯,還是這個符號。如果在索引器 [] 中使用它,它將充當索引的作用。
^ 運算符在 C# 8.0 和更高版本中提供,指示序列末尾的元素位置。例如,^1 指向序列的最後一個元素,^length 指向序列的第一個元素。

複製代碼

int[] xs = new[] { 0, 10, 20, 30, 40 };
int last = xs[^1];
Console.WriteLine(last);  // output: 40

所以當我們需要逆序來訪問索引器的時候就不需要寫成 : array[array.length - i] 了,直接^i 就可以了。

Null 條件運算符 ?. 和 ?[]

僅當操作數的計算結果爲非 null 時,null 條件運算符纔會將成員訪問 ?. 或元素訪問 ?[] 運算應用於其操作數;否則,將返回 null。

複製代碼

A?.B?.Do(C);
A?.B?[C];

該操作符相信很多小夥伴早就使用起來了,畢竟可以直接省略掉我們的 if(A==null),大幅提高了我們的編碼流暢度。

範圍運算符 ..

這個操作符很好玩,它是最新版本C#中才更新的。
.. 運算符在 C# 8.0 和更高版本中提供,指定索引範圍的開頭和末尾作爲其操作數。

複製代碼

int[] numbers = new[] { 0, 10, 20, 30, 40, 50 };
int start = 1;
int amountToTake = 3;
int[] subset = numbers[start..(start + amountToTake)];
Display(subset);  // output: 10 20 30

它可以結合上面的索引運算符 ^ 一同使用,比如:

複製代碼

int margin = 1;
int[] inner = numbers[margin..^margin];
Display(inner);  // output: 10 20 30 40

所以我們就可以不用去for循環然後再來截取原視數組的部分了。

類型測試運算符 is

該關鍵字其實大家也很熟悉,但是在C# 7之後,它新增了:有模式匹配的類型測試。

複製代碼

object iBoxed = i;
if (iBoxed is int a)
{
    Console.WriteLine(a);
}

在常規的類型測試表達式後面跟上一個變量,則該變量會轉換爲測試運算後的結果。這樣就不需要我們再去做一次判斷了。

一說到這裏,我突然想到如果以後的C#能夠支持這種表達式就好了,雖然只是YY????:

複製代碼

if(cacl() != null)
{
    var result = cacl();
    //use result do something 
}

//如果能更改爲這樣就好了
if(cacl() result !=null)
{
    //use result do something 
}

Null 合併運算符 ??

該運算符也是非常有用的。如果左操作數的值不爲 null,則 null 合併運算符 ?? 返回該值;否則,它會計算右操作數並返回其結果。 如果左操作數的求值結果爲非 null,則 ?? 運算符不會對右操作數求值。

複製代碼

int? a = null;
int b = a ?? -1;
Console.WriteLine(b);  // output: -1

這樣就避免了我們每次都會去寫一個 if(xx = null),從而大大簡化我們的代碼。
並且它還可以一直推算下去:

複製代碼

a ?? b ?? c

而在C# 8之後,??運算符還提供了合併運算的版本 ??= 。

複製代碼

b = b?? a;
//等同於
b??=a;

所以咱們經常對List判斷是否爲空,賦予初始值的操作,現在只需要一句話就完成了:

複製代碼

someList ??= new List<int>()).Add(5);

再結合上面的一些操作符來使用:

複製代碼

double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
{
    return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
}

總結

所以現在咱們再來看一些感覺奇怪的符號就覺得自然得多了,這些運算符不知道幫助咱們省略掉了多少的if- else。

本文只是選取了一些不常見的運算符來介紹,而常見的 " | "、“ & ” ,“ ?. ” 等運算符相信大家用的也比較多了,所以就不再提及。 還有就是關於指針的一些操作符,比如: " -> " , “ * ”等也沒有涉及。

當然,如果您用的是最新的C#版本,你可以使用所有的這些簡寫運算符,如果您使用的是以往的版本,請確保該運算符被支持喲。

本篇文章也不屬於什麼技術分享。不過有時候這些基礎的東西往往會對咱們編碼提供很大的便利性。

人生如夢,韶華白首,轉瞬即逝,因而生應盡歡。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章