[讀書筆記]C#學習筆記七: C#4.0中微小改動-可選參數,泛型的可變性


[讀書筆記]C#學習筆記七: C#4.0中微小改動-可選參數,泛型的可變性

前言html

下面就開始總結C#4.0的一些變化了, 也是這本書中最後的一點內容了, 這一部分終於要更新完了. 同時感受再來讀第二遍也有不同的收穫. 今天很嗨的是武漢下雪了,明天週六,一切都是這麼美好.哈哈哈.
主要內容有: 可選參數和命名實參, 泛型的可變性, 動態類型數組

1,可選參數和命名實參
1.1可選參數
可選參數和命名實參就如同一對好基友, 由於它們常常一塊兒使用.
可選參數重在"可選", 即在調用方法時, 該參數能夠明確指定實參, 也能夠不指定實參.以下代碼:微信

 

複製代碼

 1 class Program 2 { 3     static void Main() 4     { 5         TestMethod(1, 2, "WangMeng"); 6         TestMethod(2, 3); 7         Console.ReadKey(); 8     } 9 10     //帶有可選參數的方法11     static void TestMethod(int x, int y = 10, string name = "BarryWang")12     {13         Console.Write("x = {0} y = (1) name = {2};", x, y, name);14     }15 }

複製代碼

 

打印結果以下圖:
框架

 


是否是有一種很神奇的感受? 這就是可選參數的好用之處, 特別是對於一個系統的後期維護很好使用, 在真實的項目中我也使用過這樣的用法, 以下例:
ide

在咱們作的系統中切換User有SwitchUser(不lougout當前user,而後添加新的user登錄)和TransferUser(logout當前user,而後登錄新的user)兩種方式
可是系統又會進行對登錄的user數量進行限制, 而SwitchUser和TransferUser使用的都是同一個限定Check方法,而兩種對User的操做方式不一樣,因此致使TransferUser會出現問題.
這裏的解決方案就是仍然使用同一個Check方法,可是給這個Check方法新添加一個可選參數來判斷究竟是執行的哪一個操做, 而後根據不一樣的操做去作相應的修改.post

在使用可選參數時, 須要注意一下幾個約束條件:
(1)全部可選參數必須位於必選參數以後.
(2)可選參數的默認值必須爲常亮.
(3)參數數組(有params修飾符聲明)不能作爲可選參數
(4)用ref或out關鍵字標識的參數不能被設置爲可選參數學習

看到這裏咱們就能夠發現可選參數的最大的優勢就是便於系統後期的維護. 其餘的優勢還有待發現.url

1.2命名實參
若是一個系統中有兩個可選參數, 而咱們想省略掉第一個可選參數怎麼辦呢? 命名實參這個時候就能夠幫助咱們了.spa

複製代碼

 1 class Program 2 { 3     static void Main() 4     { 
 5         //省略name參數 6         TestMethod(2, 14); 7         //省略y參數和name參數 8         TestMethod(2); 9         //爲不分實參指定名稱, 經過使用命名實參, 只省略y參數10         TestMethod(2, name : "WangMeng");11         //爲全部實參指定名稱12         TestMethod(x: 2, y: 20, name: "Hello");13         Console.ReadKey();14     }15 16     //帶有兩個可選參數的方法17     static void TestMethod(int x, int y = 10, string name = "BarryWang")18     {19         Console.WriteLine("x = {0}, y = {1}, name = {2}", x, y, name);20     }21 }

複製代碼

打印結果以下圖:code

有了命名實參, 可選參數的變得更增強大了是否是? 哈哈, 確實是這樣.

2,泛型的可變性
在C#2.0 中, 泛型並不具有可變性, 這種是指斜變性和逆變性. 而在C#4.0中引入了泛型的協變性和逆變性.

2.1協變性
協變性指的是泛型類型參數能夠從一個派生類隱式轉化爲基類. 你們能夠這樣記憶: 協變性即和諧(與"協"同音)的變化,
從派生類轉換爲基類, 就如同所子女長的像父母同樣, 聽起來很是和諧. 這樣就很容易記住協變了.
C#4.0引入out關鍵字來標記泛型參數, 以示其支持協變性. 爲了更好的進行說明, 下面用.Net類苦中的IEnumerable<out T>接口爲例作演示:

複製代碼

 1 class Program 2 { 3     static void Main() 4     { 
 5         //初始化泛型實例 6         List<object> listObject = new List<object>(); 7         List<string> listStrs = new List<string>(); 8  9         listObject.AddRange(listStrs);//成功10         listStrs.AddRange(listObject);//失敗11     }12 }

複製代碼

在以上代碼中, AddRange方法接收的參數類型爲IEnumerable<T>, 該接口的定義爲IEnumerable<out T>, 由於其泛型參數有out關鍵字標識,
因此IEnumerable<T>泛型的類型參數T支持協變性, 則可將List<string>轉化爲IEnumerable<string>(這是被繼承的協變性支持的. 由於List<T>實現了IEnumerable<T>接口).
又由於類型參數支持協變性, 因此能夠進一步把IEnumerable<string>轉化爲IEnumerable<object>

2.2逆變性
逆變性指的是泛型類型參數能夠從一個基類隱式地轉化爲派生類,C#4.0引入in關鍵字來標記泛型參數, 以示其支持逆變性.
下面使用.Net類庫中的接口public interface IComparer<in T>爲例進行演示:

複製代碼

 1 class Program 2 { 3     static void Main(string[] args) 4     { 5         List<object> listobject = new List<object>(); 6         List<string> liststrs = new List<string>(); 7         // AddRange方法接收的參數類型爲IEnumerable<T> collection 8         // 下面的代碼是傳入的是List<string>類型的參數。 9         // 在MSDN中能夠看出這個接口的定義爲——IEnumerable<int T>。10         // 因此 IEnumerable<T>泛型類型參數T支持協變性,因此能夠11         // 將List<string>轉化爲IEnumerable<string>(這個是繼承的協變性支持的)12         // 又由於這個IEnumerable<in T>接口委託支持協變性,因此能夠把IEnumerable<string>轉化爲——>IEnumerable<object>類型。13         // 因此編譯器驗證的時候就不會出現類型不能轉化的錯誤了。14         listobject.AddRange(liststrs);  //成功15 16         ////liststrs.AddRange(listobject); // 出錯17 18         IComparer<object> objComparer = new TestComparer();19         IComparer<string> objComparer2 = new TestComparer();20 21         // List<string>類型的 liststrs變量的sort方法接收的是IComparer<string>類型的參數22         // 然而下面代碼傳入的是 IComparer<object>這個類型的參數,要編譯成功的話,必須可以轉化爲IComparer<string>這個類型23         // 正是由於IComparer<in T>泛型接口支持逆變,因此支持object轉化爲string類型24         // 因此下面的這行代碼能夠編譯經過,在.Net 4.0以前的版本確定會編譯錯誤,25         // 你們能夠把項目的目標框架改成.Net Framework 3.5或者更加低級的版本26         // 這樣下面這行代碼就會出現編譯錯誤,由於泛型的協變和逆變是C# 4.0 中新增長的特性,而.Net 4.0對應於C# 4.0。27         liststrs.Sort(objComparer);  // 正確28 29         // 出錯30         ////listobject.Sort(objComparer2);31     }    
32 }33 34 public class TestComparer : IComparer<object>35 {36     public int Compare(object obj1,object obj2)37     {38         return obj1.ToString().CompareTo(obj2.ToString());39     }40 }

複製代碼


在以上代碼中, listStrs變量的Sort應接收IComparer<string>類型的參數, 雖然傳入的實參是IComparer<objcet>類型,
但由於IComparer<in T>泛型接口支持逆變, 因此可將object轉化爲string類型.

2.3協變和逆變的注意事項
(1)只有接口和委託才支持協變和逆變, 類或泛型方法的類型參數都不支持協變和逆變
(2)協變和逆變只適用於引用類型, 值類型不支持協變和逆變(例如List<int>沒法轉化爲IEnumerable<objcet>)
(3)必須顯式地用in或out來標記類型參數
(4)委託的可變性不要再多播委託中使用

3,動態類型
在C#4.0中, 微軟引入了dynamic管家你來定義動態類型. 當咱們使用由dynamic關鍵字限制的變量時, 編譯器並不知道它的類型, 該類型智能在程序運行時才能被肯定.
動態類型的定義爲: dynamic i = 5;
動態類型和靜態類型到底有什麼不一樣呢?

1 object obj = 10;2 obj = obj + 10;//出現變異錯誤3 dynamic i = 10;4 i = i + 10;

解析:
在以上代碼中, 第一行的obj爲objec他類型, 而編譯器卻檢測出"+"運算符沒法應用於object和int類型.
要讓編譯器經過, 咱們必須使用強制類型轉換, 把object轉換爲int. 即obj = (int)obj + 10;

可是動態類型的引入到底有什麼好處呢?
1,能夠減小強制類型轉換的使用. 由於動態類型是在程序運行時才被肯定, 使用它能夠避免代碼進行強制類型轉換,從而使代碼看起來更加簡潔.
2,調用Python等動態語言. 動態類型除了能夠減小強制類型轉換外, 還可讓咱們在C#語言中調用Python這樣的動態語言.

這裏對動態類型介紹的很少, 主要是介紹了一個dynamic關鍵字, 若是之後用到再來百度就行了.

 

PS: 想爲本身的文字多增長一點內容, 之後每一個帖子後面都會加一些口語小貼士, 這些都是本身平時看過的. 英語真的很重要, 這裏不用我多說你們應該都知道的.

口語小貼士:
A fool never learns.
傻瓜永遠學不會
A little bird told me.
我據說的
Are you out of your mind?
你瘋了嗎?
Are you pulling my leg?
你在開我玩笑嗎?
As far as I'm concerned.
就我而言

分類: C#基礎系列讀書筆記

好文要頂 關注我 收藏該文  

一枝花算不算浪漫

相關文章
相關標籤/搜索