C#逆變和協變的理解-----為什麼逆變可以把Object類型的型別參數轉換成String類型的型別參數

來源:互聯網
上載者:User

標籤:line   安全   介面   namespace   show   基類   誤區   強制轉換   指定   

根據可變性的規則,只有介面和委託可以標記可變性。且只有型別參數為參考型別時才可以利用可變性。

不變性:泛型型別的參數不能改變,這表示一個建立一個MyInterface<String>類型的對象時,賦值給它的只能是MyInterface<String>類型

 1 namespace ContravariantAndCovariant 2 { 3     public interface MyInterface<T>//沒有指定任何可變性,說明這個介面的型別參數是不變的 4     { 5         void Show(T t); 6     } 7  8     public class ShowObject : MyInterface<Object> 9     {10         public void Show(object t)11         {12             Console.WriteLine(t.ToString());13         }14     }15 16     public class ShowString : MyInterface<String>17     {18         public void Show(string t)19         {20             Console.WriteLine(t);21         }22     }23 24     public class ShowInt : MyInterface<Int32>25     {26         public void Show(int t)27         {28             Console.WriteLine(t.ToString());29         }30     }31 32     class Program33     {34         static void Main(string[] args)35         {36             //正確37             MyInterface<String> str_invariant = new ShowString();//只能賦值MyInterface<String>類型38             //錯誤39             MyInterface<String> str_contravariant = new ShowObject();//當賦值其它類型的時候,編譯器會報錯40             //CS0266    無法將類型“ContravariantAndCovariant.ShowObject”隱式轉換為“ContravariantAndCovariant.MyInterface<string>”。存在一個顯式轉換(是否缺少強制轉換?)    41 42         }43     }44 45 }

逆變性:泛型的型別參數可以從一個類變成它的衍生類別,比如:可以把MyInterface<object>轉換成MyInterface<string>。逆變用in表示,因為它出現在輸入的位置(方法的參數),in 就是進去的意思。

 1 namespace ContravariantAndCovariant 2 { 3     public interface MyInterface<in T>//用in關鍵字指定T的逆變性 4     { 5         void Show(T t);//T是參數類型 6     } 7  8     public class ShowObject : MyInterface<Object> 9     {10         public void Show(object t)11         {12             Console.WriteLine(t.ToString());13         }14     }15 16     public class ShowString : MyInterface<String>17     {18         public void Show(string t)19         {20             Console.WriteLine(t);21         }22     }23 24     public class ShowInt : MyInterface<Int32>25     {26         public void Show(int t)27         {28             Console.WriteLine(t.ToString());29         }30     }31 32     class Program33     {34         static void Main(string[] args)35         {36             MyInterface<object> obj = null;37             MyInterface<string> str = obj;//可以把MyInterface<object>類型轉換為MyInterface<string>類型38         }39     }40 41 }

協變性:泛型的型別參數可以從一個類變成它的基類,比如:可以把MyInterface<string>轉換成MyInterface<object>。逆變用out表示,因為它出現在輸出的位置(方法傳回值),out 就是出的意思。

 1 namespace ContravariantAndCovariant 2 { 3     public interface MyInterface<out T>//用out關鍵字指定T的協變性 4     { 5         T Show(); //T是傳回型別 6     } 7  8     public class ShowObject : MyInterface<Object> 9     {10         public object Show()11         {12             return null;13         }14     }15 16     public class ShowString : MyInterface<String>17     {18         public string Show()19         {20             return null;21         }22     }23 24     class Program25     {26         static void Main(string[] args)27         {28             //錯誤29             //MyInterface<object> obj = null;30             //MyInterface<string> str = obj;//不能把MyInterface<object>類型轉換為MyInterface<string>類型31 32             //正確33             MyInterface<string> str = null;34             MyInterface<object> obj = str;//可以把MyInterface<string>類型轉換成MyInterface<Object>類型35         }36     }37 }

CLR是要保證類型的轉換是安全的,協變性還好理解,子類是可以轉換成父類的,因為子類對象中包括父類對象的所有成員。這個轉換是安全的。

但是逆變的話,父類轉換成子類是不安全的,當不能裡氏轉換的時候,父類對象中並沒有子類的所有成員。

其實這麼看的話是有一個誤區,就是關於引用和對象。當逆變的時候,比如上面逆變的代碼中:

MyInterface<object> obj = null;

MyInterface<string> str = obj;

str.Show("123")

str是MyInterface<string>類型的變數,但是它引用的對象是MyInterface<Object>類型的,所以當我們調用Show()方法的時候,其實是obj.Show();

obj的參數是object類型的,我們傳入的是一個string類型,string---->object的轉換是安全的。所以逆變是安全的!

同理的話,協變:

MyInterface<string> str = null;

Myinterface<object> obj = str;

 object  result = obj.show();

可以看到obj是MyInterface<object>類型的變數,但是它引用的對象是MyInterface<string>類型,所以當我們調用Show()方法的時候,其實是str.Show(),

它返回的是string類型,但是obj.Show()返回的是一個object類型,所以我們用一個object類型的變數result去接收傳回值,最終變成 string ----->object類型的轉換,所以協變是安全的。

C#逆變和協變的理解-----為什麼逆變可以把Object類型的型別參數轉換成String類型的型別參數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.