作者ccorn (玉米)
看板C_Sharp
標題[問題] 泛型使用時機/參數傳入泛型或是interface
時間Thu Sep 6 17:28:15 2018
最近新學了泛型很開心,很多東西都可以拿來共用。
但是感覺自己有點走火入魔,用得太多,不知道參數到底要傳入泛型還是介面。
寫法一
public void DoSomething<T>(T obj)
where T: ISomething
寫法二
public void DoSomething(ISomething obj)
之前常常寫寫法一,現在發現寫法二也可以編譯和正確執行
不知道寫法一和寫法二的差別是習慣問題還是根本用錯泛型了...
希望有人可以替我解答,感謝!!
如果我真的用錯泛型了,也想問一下泛型正確的使用時機是什麼?
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 59.120.231.91
※ 文章網址: https://webptt.com/m.aspx?n=bbs/C_Sharp/M.1536226098.A.8C9.html
1F:推 s4300026: 一樣的方法定義用泛型,一樣的方法宣告用介面09/06 19:09
2F:推 s4300026: (魚,蟲,人,菌),執行 “進食” 用介面。 (老師,09/06 19:22
3F:→ s4300026: 學生,家長,督察),執行 “用現金付帳” 用泛型。09/06 19:22
是說進食的實作根據物種差很多,用現金付帳的實作各種身份都一樣嗎?
那我有點不太懂為什麼用這兩個狀況判斷泛型與否,是否跟樓下c大說的轉型消耗有關?
感謝你的回應~
4F:推 CloudyWing: 以這範例來說,除非method裡面可能會把介面轉型成實際09/06 23:35
5F:→ CloudyWing: 型別,不然是2吧09/06 23:35
6F:推 CloudyWing: 以這情況,其實你呼叫起來幾乎沒差別,如果用介面就09/06 23:43
7F:→ CloudyWing: 不會有轉型損耗的,其實用介面就可以了,有轉型損耗的09/06 23:44
8F:→ CloudyWing: 就要考慮泛型或是泛型介面09/06 23:45
了解,那如果這樣可以使用介面的狀況寫成泛型,會被當成dirty code或是不易讀或是效
能差嗎?
感謝你的回應~
※ 編輯: ccorn (116.241.1.187), 09/07/2018 00:27:16
※ 編輯: ccorn (116.241.1.187), 09/07/2018 00:56:04
9F:推 CloudyWing: 我個人覺得沒太大差別,然後修正一下,說轉型損耗不精09/07 01:32
10F:→ CloudyWing: 準,不用自行做型別檢查或額外做轉型09/07 01:34
11F:→ CloudyWing: DoSomething()裡面如果只在意ISomething,例如只是呼09/07 02:02
12F:→ CloudyWing: 叫ISomething的某個方法,那就是介面就好 09/07 02:03
13F:→ CloudyWing: 但如果你在乎的是ISomething的延伸類別 09/07 02:04
14F:→ CloudyWing: 那你可能就必須在method去判斷參數是ISomething的哪個 09/07 02:05
15F:→ CloudyWing: 延伸類別,或是利用泛型,讓使用者可以延後到呼叫時決 09/07 02:09
16F:→ CloudyWing: 定,更簡單來說是你是在定義method還是呼叫method決定09/07 02:10
17F:→ CloudyWing: 有效的型別來決定是interface還是泛型,感覺越講越亂.09/07 02:11
18F:→ CloudyWing: 想到一個爛例子可以說明InterfaceA有定義methodA 09/07 02:39
19F:→ CloudyWing: ClassA實作MethodA;ClassB繼承MethodA,new MethodA09/07 02:40
20F:→ CloudyWing: 上面打錯,ClassB繼承ClassA,又用new定義同名MethodA09/07 02:41
21F:→ CloudyWing: 如果你今天在意的是InterfaceA,不管傳入參數型別是 09/07 02:43
22F:→ CloudyWing: 哪個,DoSomething()裡呼叫都是實作介面的MethodA 09/07 02:44
23F:→ CloudyWing: 那就是作法二,如果你是要讓呼叫DoSomething的人可以 09/07 02:46
24F:→ CloudyWing: 決定是要呼叫哪個Class的MethodA,那就是作法一 09/07 02:48
25F:→ CloudyWing: 當然正常不會用同名Method玩,而是搭配delegate使用 09/07 02:49
了解,那我還是乖乖改成介面好了><
其實我泛型用太多,同事有點看不懂
26F:推 s4300026: 不好意思,我把你的問題看成 "宣告方法" 時,要用介面 09/07 09:07
27F:→ s4300026: 還是泛型。09/07 09:07
28F:推 s4300026: 如果考慮傳入值要用哪一種的話,能用介面,就用介面。09/07 09:17
29F:→ s4300026: 我會用泛型的情況,像是方法內會用到實作本體,像是new09/07 09:17
30F:→ s4300026: 之類的。09/07 09:17
了解,乖乖改成介面><
31F:→ testPtt: where T : new()09/07 09:59
我懂你 實體化時
32F:推 Litfal: 介面和委派可以給定in或out去指定輸入或產出。你要從更高09/07 15:09
33F:→ Litfal: 的視野去理解這件事,這是SA的技能之一。09/07 15:10
我以為SA只是做文字的系統分析而已?!
34F:推 s4300026: 樓上的意思是,如果是介面,就可以只吞我定義的介面輸入 09/07 18:43
35F:→ s4300026: ,但泛型的目標是我力求吞任何類型的輸入 09/07 18:43
36F:→ s4300026: 是這樣解釋嗎? 09/07 18:43
37F:推 CloudyWing: 32樓講的是泛型介面才有,想知道可以查協變和逆變 09/08 10:35
之前看協變逆變看不太懂,這樣一說就通了!這版強者真多><以後要多來發問了
※ 編輯: ccorn (116.241.1.187), 09/08/2018 23:00:01
38F:推 EnjoyLife000: 泛型是針對物件做處理 09/14 23:33
39F:→ EnjoyLife000: 介面是對物件做的規定 09/14 23:33
40F:→ EnjoyLife000: 經常兩個會合在一起用,像是List<T>,裡面有很多 09/14 23:34
41F:→ EnjoyLife000: ToXXX() 然後他會約束where T: 什麼介面或是Class 09/14 23:35
42F:→ EnjoyLife000: 但TOXXX都是針對T做操作。 如果今天你的Method裡面 09/14 23:36
43F:→ EnjoyLife000: 針對T的類型都會呼叫同一個方法,這就要做介面 09/14 23:37
44F:→ EnjoyLife000: 推文好難回,到此為此.. 09/14 23:37