最近發現 C#7 以後的 is 是愈來愈看不懂了,乍一看花裏胡哨的,不過當我靜下心來仔細研讀,發現這 is 是愈來愈短小精悍,並且還特別語義化,那怎是一個爽字了得😄,這一篇就和你們簡單聊一聊。git
相信學過 C# 的朋友都會知道 is 是幹嗎的,並且還常常和 as 一塊兒比較,前者通常作兼容性檢測,後者通常作兼容性轉換,這裏我就舉個例子吧:github
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 都是類型兼容的,很是簡單。sql
然而在實際編碼中,我相信有不少朋友都會在後續的過程當中用到 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 的功能,那就🐂👃了,我以爲這個急需加強。code
也終於在 C#7 以後對 is 進行了翻天覆地的語法糖改造,致使你初看已經不明白啦😄😄😄,下面我就一一舉例來講明吧。blog
如今就來看一下怎麼用新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 變量,哈哈,有點意思吧,爲了驗證是否如我所說,用反編譯工具看看。ip
能夠看到,在實操中,編譯器都用 as 進行了還原,不過從代碼流暢性來看,ILSpy更🐂👃一點。字符串
除了和類實例比較以外,還能夠和 int,string,tuple ...進行比較, 代碼以下:
object e = 150; //字符串比較 if (e is "hello") { } //整形比較 if (e is 10) { } //tuple 比較 if (e is (10, 20)) { }
你們在寫 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 中就習覺得常呢? 其實反編譯過來也沒啥,就是一個 == 判斷,以下代碼:
如今你們都看到了 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 的方式轉換一下哈,以下圖所示:
當 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# 大法🐂👃。
更多高質量乾貨:參見個人 GitHub: dotnetfly