當泛型方法推斷,擴展方法遇到泛型類型in/out時。。。

  說到泛型方法,這個是.net 2.0的時候引入的一個重要功能,c#2.0也對此作了非常好的支持,可以不需要顯試的聲明泛型類型,讓編譯器自動推斷,例如:

1 void F<T>(T value){}
2 //...
3 int i = 0;
4 F(i);

此時,編譯器可以自動推導出這里的T就是int,這極大的方便了我們寫代碼的效率。

  說到擴展方法,這個是.net 3.5的時候引入的另一個重要功能,c#3.0也在linq中大量的應用這個功能,當擴展方法是擴展一個泛型的類型時,顯然也不需要我們指定具體的泛型類型,編譯器會為我們自動推斷,例如:

1 static void F<T>(this List<T> list){}
2 //...
3 List<int> list = new List<int>();
4 list.F();

  最后說到協變和逆變(也就是c#中的in/out),這個是.net 4.0的時候引入的一個重要的功能,例如:

1 Func<string> foo = () => "Foo";
2 Func<object> bar = foo;

  然后,我們將泛型方法推斷和協變和逆變放在一起:

1 public static void Foo(this Action<string> action){}
2 //...
3 Action<object> action = o => {};
4 action.Foo();

  看起來很不錯,不過要是遇到些復雜點的會怎么樣?

1 public static void Foo(this IEnumerable<IEnumerable<object>> that) {}
2 //...
3 List<List<string>> bar = new List<List<string>>();
4 bar.Foo();

  看到這里相信所有都為c#的in/out拍手叫好,不過別急,除了out+out我們還可以玩令人抓狂的in+in:

1 public static void Foo(this Action<Action<object>> that) {}
2 //...
3 Action<Action<string>> action = a => a("O_O");
4 action.Foo();

  看到這里有沒有發現什么問題?如果你沒覺得有什么不舒服的感覺,說明你一定是懂協變和逆變的高手或是完全不懂的初學者。

  先想下定義:Action<in T>,T 是in的,也就是Action<object>里面的object可以被string這樣更具體的類型替代,而這里Action<Action<string>>里面的Action<string>被Action<object>替代了,怎么看都感覺有些怪異,不過在細細品味一下,就可以發現這個結果是完全合理的。string雖然比object更具體,不過一個接受string的方法可比一個接受object的方法更抽象,所以可以簡單的得到一個結論:in+in=>out

  文章要是到這里結束,估計很多人就認為本文是對c#的無比贊美了吧,不過,重點是這里,別忘了,多個泛型參數可以玩出很多猥瑣的東西,例如,雙/多泛型鎖定(隨便起的名字):

1 public static void Foo<T>(this Action<T, T> that) {}
2 //...
3 Action<string, object> action = (s, o) => {};
4 action.Foo();

  c#編譯器對擴展方法支持的確是有一手,這么變態的T也可以被推斷出是object,不得不佩服一把,再來看看out的情況(別忘了前面的結論in+in=>out):

1 public static void Foo<T>(this Action<Action<T>, Action<T>> that) {}
2 //...
3 Action<Action<string, object>> action = (s, o) => {};
4 action.Foo();

  c#編譯器依然表現出專業的結果,正確的推斷出了T應當是string,不過,泛型方法的類型推斷卻完全是另外一番風景:

1 public void Foo<T>(Action<T, T> that) {}
2 //...
3 Action<string, object> action = (s, o) => {};
4 Foo(action); // failed.
5 Foo<object>(action); // failed.
6 Foo((Action<object, object>)action); // succeeded.

  看到這個結果是不是想大罵c#編譯器:這也太山寨了吧。

  別急,我們還可以玩得更加浮云:

1 public static Foo<T>(this Action<Action<T>, Action<T>> that) {}
2 // ...
3 Action<Action<List<string>>, Action<ArrayList>> bar = null;
4 bar.Foo(); // failed.
5 bar.Foo<IEnumerable>(); // succeeded.

  或者這個:

public static Foo<T>(this Action<T, T> that) {}
// ...
Action<IEnumerable<char>, IComparable<string>> action = null;
action.Foo(); // failed.
action.Foo<string>(); // succeeded.

  c#編譯器顯然不想瞎猜T的類型是什么,要求必須編程者明確指出T的具體類型。

轉載于:https://www.cnblogs.com/vwxyzh/p/3704220.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/375872.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/375872.shtml
英文地址,請注明出處:http://en.pswp.cn/news/375872.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AOP相關

實現AOP的技術&#xff0c;主要分為兩大類&#xff1a;一是采用動態代理技術&#xff0c;利用截取消息的方式&#xff0c;對該消息進行裝飾&#xff0c;以取代原有對象行為的執行&#xff1b;二是采用靜態織入的方式&#xff0c;引入特定的語法創建“方面”&#xff0c;從而使得…

操作系統上機作業--根據萊布尼茲級數計算PI(1)(多線程)

pi1.c: 使用2個線程根據萊布尼茲級數計算PI ? 萊布尼茲級數公式: 1 - 1/3 1/5 - 1/7 1/9 - ... PI/4 ? 主線程創建1個輔助線程 ? 主線程計算級數的前半部分 ? 輔助線程計算級數的后半部分 ? 主線程等待輔助線程運行結束后,將前半部分和后半部分相加實現思路&#xff1…

四種途徑將HTML5 web應用變成android應用

作為下一代的網頁語言&#xff0c;HTML5擁有很多讓人期待已久的新特性。HTML5的優勢之一在于能夠實現跨平臺游戲編碼移植&#xff0c;現在已經有很多公司在移動設備上使用HTML5技術。隨著HTML5跨平臺支持的不斷增強和智能手機的迅速普&#xff0c;HTML5技術有著非常好的發展前景…

操作系統上機作業--根據萊布尼茲級數計算PI(2)(多線程)

pi2.c: 使用N個線程根據萊布尼茲級數計算PI ? 與上一題類似&#xff0c;但本題更加通用化&#xff0c;能適應N個核心&#xff0c;需要使用線程參數來實現 ? 主線程創建N個輔助線程 ? 每個輔助線程計算一部分任務&#xff0c;并將結果返回 ? 主線程等待N個輔助線程…

html 16進制 轉換成字符串,js 字符串和16進制的互相轉換

字符串轉16進制function strToHexCharCode(str) {if(str "")return "";var hexCharCode [];hexCharCode.push("0x");for(var i 0; i < str.length; i) {hexCharCode.push((str.charCodeAt(i)).toString(16));}return hexCharCode.join(&qu…

數組以及冒泡排序

數組 1、概念&#xff1a;可以幫我一次聲明多個同類型的變量&#xff0c;這些變量再內存中是連續存儲的。 2、聲明語法&#xff1a;數據類型[] 數組名 new 數據類型[數組長度] 數組長度&#xff1a;一次要聲明的同類型的變量個數。是在定義這個數組的時候就確定了&#xf…

jQuery觸發a標簽的點擊事件無效

1 <a id"workFrame" href"pages/work.html" target"FrameBox">首頁</a> 2 3 $("#workFrame").tigger("click"); 上述的代碼&#xff0c;其實挺正常的&#xff0c;但是怎么也觸發不了a標簽的cli…

操作系統上機作業--多線程排序

sort.c: 多線程排序 ? 主線程創建一個輔助線程 ? 主線程使用選擇排序算法對數組的前半部分排序 ? 輔助線程使用選擇排序算法對數組的后半部分排序 ? 主線程等待輔助線程運行結束后,使用歸并排序算法歸并數組的前半部分和后半部分 實現思路&#xff1a; ARRAY_CO…

jdk5下載鏈接

查看jdk版本 java -versionJDK下載 最新版本http://www.oracle.com/technetwork/java/javase/downloads/index.htmlJDK下載 版本1.5.22http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javase5-419410.html#jdk-1.5.0_22-oth-JPR JDK…

html的細節優化,網站頁面優化細節詳解

原標題&#xff1a;網站頁面優化細節詳解SEO頁面優化是繼SEO結構優化之后&#xff0c;另一個重要優化地方;頁面標題在每個頁面中的關鍵位置&#xff0c;出現目標關鍵詞&#xff0c;這是我們做頁面優化的基礎思路&#xff0c;關鍵詞位置&#xff0c;都有哪些呢?第一個是關鍵位置…

突擊優化算法!

Matlab語言可以與C/C語言轉換或調用。 Matlab語句&#xff1a;load name 把name中文件的所有變量載入到工作空間中。save name 保存工作空間的變量到name.mat中。 cholesky分解把一個正定矩陣分為一個下三角矩陣和它轉置矩陣的乘積。 兩種創立符號函數的方法&#xff1a;sym函數…

操作系統上機作業--使用條件變量解決生產者、計算者、消費者問題(多線程)

pc1.c: 使用條件變量解決生產者、計算者、消費者問題 /* ? 系統中有3個線程&#xff1a;生產者、計算者、消費者 ? 系統中有2個容量為4的緩沖區&#xff1a;buffer1、buffer2 ? 生產者生產a、b、c、‘d、e、f、g、h八個字符&#xff0c;放入到buffer1 ? 計算者從b…

淘寶代碼和html區別,taobao.html

taobao主題市場女裝 /男裝 /內衣 >鞋靴 /箱包 /配件 >童裝玩具 /孕產 /用品 >家電 /數碼 /手機 >女裝 /男裝 /內衣 >鞋靴 /箱包 /配件 >童裝玩具 /孕產 /用品 >家電 /數碼 /手機 >女裝 /男裝 /內衣 >鞋靴 /箱包 /配件 >童裝玩具 /孕產 /用品 >…

程序各個段text,data,bss,stack,heap

網上找了一堆資料學習一下,了解這些, 有助于規化程序結構,優化代碼; 使用gcc編譯出來的程序,用size可以查看程序結構和大小, 如 1: #size hello 2: Text data bss dec hex filename 3: 778 200 4 982 3D6 hello 所以一個可執行的程序文件,結構分三部分: .text 代碼段,用來存…

讓 keil MDK 支持C99

打開options fot target-> C/C 在 Misc Controls 中添加 --c99. 轉載于:https://www.cnblogs.com/svchao/p/4585034.html

html從日期格式中獲取年,js轉換日期格式(Js獲取年月日及時間轉換)

1、獲取年、月、日和將時間戳轉換成日期格式// 簡單的一句代碼var date new Date(時間戳); //獲取一個時間對象/**1. 下面是獲取時間日期的方法&#xff0c;需要什么樣的格式自己拼接起來就好了2. 更多好用的方法可以在這查到 -> http://www.w3school.com.cn/jsref/jsref_o…

月半小夜曲

轉載于:https://www.cnblogs.com/yesihoang/p/4588319.html

操作系統上機作業-- 使用信號量解決生產者、計算者、消費者問題(多線程)

pc2.c: 使用信號量解決生產者、計算者、消費者問題 ? 功能和前面的實驗相同&#xff0c;使用信號量解決 實現思路: 生產者、計算者、消費者三者之間的關系和上一個編程任務一樣&#xff0c;不一樣的是&#xff0c;將互斥量、條件變量封裝起來作為信號量&#xff0c;處理方…

Singleton 單件

模式分類 從目的來看&#xff1a; -創建型&#xff08;Creational&#xff09;模式&#xff1a;負責對象創建 -結構型&#xff08;Structural&#xff09;模式&#xff1a;處理類與對象間的組合 -行為型&#xff08;Behavioral&#xff09;模式&#xff1a;類與對象交互中的職責…

引入struts html標簽,【學習】Struts標簽之html標簽

html:multiboxhtml:multibox標簽生成多個checkbox。當您要使用大量的checkbox時使用這個標簽非常方便&#xff0c;可以使您避免在ActionForm中聲明大量的boolean類型的變量&#xff0c;帶之以一個數組就行了。注意:為了正確的處理沒有選中的checkbox您必須在reset()中設置數組的…