C# 中的 is 真的是越来越强大,越来越语义化
一:背景
1. 講故事
最近發現 C#7 之后的 is 是越來越看不懂了,乍一看花里胡哨的,不過當我靜下心來仔細研讀,發現這 is 是越來越短小精悍,而且還特別語義化,那怎是一個爽字了得????,這一篇就和大家簡單聊一聊。
二:C#7 之前的 is 如何使用
1. 類型兼容性檢測
相信學過 C# 的朋友都會知道 is 是干嘛的,而且還經常和 as 一起比較,前者一般做兼容性檢測,后者一般做兼容性轉換,這里我就舉個例子吧:
static?void?Main(string[]?args){object?slot?=?new?Slot()?{?ClothesName?=?"上衣"?};if?(slot?is?Slot){Console.WriteLine($"slot?is?{nameof(Slot)}");}if?(slot?is?IComparable){Console.WriteLine($"slot?is?{nameof(IComparable)}");}}public?class?Slot?:?IComparable{public?string?ClothesName?{?get;?set;?}public?int?CompareTo(object?obj)?{return?0;}}從這個例子可以看到, object 類型的 slot 和 Slot, IComparable 都是類型兼容的,非常簡單。
2. 遺憾的地方
然而在實際編碼中,我相信有很多朋友都會在后續的過程中用到 slot 實例,而上面的這個例子,即使我用 is 檢測到了是 Slot 類型,最后我還是要 將 object slot 強轉成 Slot類型,做了一次檢測,又做了一個強轉,這就很奇葩了,如下代碼:
if?(slot?is?Slot){var?query?=?(Slot)slot;Console.WriteLine($"slot?is?{nameof(Slot)},?ClothesName={query.ClothesName}");}除非有毛病才寫這樣的代碼,干嘛不直接用 as 嘗試性轉換將兩步合為一步走呢?修改代碼如下:
var?query?=?slot?as?Slot;if?(query?!=?null){Console.WriteLine($"slot?is?{nameof(Slot)},?ClothesName={query.ClothesName}");}這就導致很多場景下,is 都被 as 替代了,搞的 is 成了一個空架子,如果 is 能合并 as 的功能,那就????????了,我覺得這個急需增強。
三:C#7 之后的 is 如何使用
也終于在 C#7 之后對 is 進行了翻天覆地的語法糖改造,導致你初看已經不明白啦????????????,下面我就一一舉例來說明吧。
1. is 和 復雜類型/簡單類型 的結合
現在就來看一下怎么用新is 解決剛才兩次轉換的問題,如下代碼:
object?slot?=?new?Slot()?{?ClothesName?=?"上衣"?};if(slot?is?Slot?query){Console.WriteLine($"slot?is?{nameof(Slot)},?ClothesName={query.ClothesName}");}這段代碼表面意思是:先用 is 檢測 slot 是否為 Slot 類型,如果是就賦值給 Slot 類型的 query 變量,哈哈,有點意思吧,為了驗證是否如我所說,用反編譯工具看看。
ILSpy 反編譯
DnSpy 反編譯
可以看到,在實操中,編譯器都用 as 進行了還原,不過從代碼流暢性來看,ILSpy更????????一點。
除了和類實例比較之外,還可以和 int,string,tuple ...進行比較, 代碼如下:
object?e?=?150;//字符串比較if?(e?is?"hello")?{?}//整形比較if?(e?is?10)?{?}//tuple?比較if?(e?is?(10,?20))?{?}2. is 和 null 的結合
大家在寫 sql 的時候判斷某一個字段是否為 null,通常都會這樣寫:username is null 或者 username is not null ,哈哈,這種寫法也被引入到 C# 中了,有意思吧,上代碼:
object?e?=?150;if?(e?is?null){Console.WriteLine("e?is?null");}if?(e?is?not?null){Console.WriteLine("e?is?not?null");}這么語義化的寫法在C#中看到是不是有點不習慣,那為啥在 sql 中就習以為常呢?其實反編譯過來也沒啥,就是一個 == 判斷,如下代碼:
3. is 和 and ,or 的結合
現在大家都看到了 is 通常是放在 if 語句中,既然在 if 語句中,那肯定有很多的邏輯判斷,這就需要結合 and,or 構建非常復雜的邏輯關系,不要眼花哦。
object?e?=?150;if?(e?is?>=?100?and?<=?200){Console.WriteLine($"e={e}?果然?大于?100?并且?小于?200");}if?(e?is?100?or?150?or?200){Console.WriteLine($"e={e}?是在?100,150,200?三個數字中");}if?(e?is?not?null?and?not?""){Console.WriteLine($"e={e},模擬?!string.IsNullOrEmpty?功能");}可以看到最后的: e is not null and not "" 其實等價于 !string.IsNullOrEmpty, 是不是有點意思哈。
這里有一點要提醒的是,上面的 e 在編譯器層面都是 object 類型,如果你想在 編譯器層面使用 int 運作,還是用 例子1 的方式轉換一下哈,如下圖所示:
4. is 和 var 的結合
當 is 和 var 結合起來就更????????了,可以實現在 if 判斷的過程中生成臨時變量,如下代碼:
int?e?=?150;if?(e?is?var?i?&&?i?>=?100?&&?i?<=?200){Console.WriteLine($"e={i}?果然?大于?100?并且?小于?200");}上面代碼中的 i 就是一個臨時變量,后面做的一切業務邏輯都是基于 i 這個臨時變量的,如果還沒有領會到精粹,沒關系,我舉一個項目中的例子吧。。。
我們公司是搞衣物洗滌自動化,也需要對線下 傳輸線上的衣服進行自動化上掛,取走和衣物組合搭配,舉個例子:找到 剛好掛了一件褲子L && 一件上衣L && 總衣服個數=2 的 掛孔號,要是還沒聽懂就算了,直接上代碼說話。
class?Program{static?void?Main(string[]?args){var?slotList?=?new?List<Slot>(){new?Slot()??{SlotID=1,?ClothesID=10,ClothesName="上衣",?SizeName=?"L"?},new?Slot()??{SlotID=1,?ClothesID=20,ClothesName="褲子",?SizeName=?"M"?},new?Slot()??{SlotID=1,?ClothesID=11,ClothesName="皮帶",?SizeName=?"X"?},new?Slot()??{SlotID=2,?ClothesID=30,ClothesName="上衣",?SizeName=?"L"?},new?Slot()??{SlotID=2,?ClothesID=40,ClothesName="褲子",?SizeName=?"L"?}};//找到?剛好掛了一件褲子L?&?一件上衣L??&?總衣服個數=2??的?掛孔號var?query?=?slotList.GroupBy(m?=>?m.SlotID).Where(m?=>m.Where(n?=>?n.SizeName?==?"L").ToList()?is?var?clothesList?&&clothesList.Count(k?=>?k.ClothesName?==?"褲子")?is?1?&&clothesList.Count(k?=>?k.ClothesName?==?"上衣")?is?1?&&m.Key?==?2).ToDictionary(k?=>?k.Key,?v?=>?v.ToList());}public?class?Slot{public?int?SlotID?{?get;?set;?}public?int?ClothesID?{?get;?set;?}public?string?ClothesName?{?get;?set;?}public?string?SizeName?{?get;?set;?}}}重點在于上面代碼的 ?m.Where(n => n.SizeName == "L").ToList() is var clothesList,這里的 clothesList 就是臨時變量,它存放了所有 尺寸L 的衣物,后續的檢索都是基于這個 clothesList,是不是大大提高了檢索速度~~~
四:總結
我覺得 is 的功能增強早就該出現了,現在終于搞定了,越來越人性化,鍵盤敲擊次數越來越少,頭發也不落了,甚至又開始第二春了,總的來說還是那句話,C# 大法????????。
總結
以上是生活随笔為你收集整理的C# 中的 is 真的是越来越强大,越来越语义化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单理解CAP-BASE
- 下一篇: c# char unsigned_dll