最佳解答者
有關介面相互繼承問題

問題
解答
-
我和忠成討論了一下覺得這可能是某些因素造成的:
(1) 一個可能原因是: C# 編譯器在 IL Code 中會將所有Interface 展開, 所以它文件乾脆也攤平寫.
(2) 一個證據是 ArrayList 的 Source Code 中其實它是這樣宣告的
public class ArrayList : IList, ICloneable
但是在文件庫上的寫法也是整個攤開變成
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
(3) 所以當你從 IL Code 反解回原始碼, 它就順勢被攤平. 所以我做了一個實驗
我先寫一個類別庫的專案, 裡面寫了一個 Interface
public interface IOnlyCollection:ICollection { }
然後我將這個類別庫編譯完成後, 用 Reflector 去開啟這個 DLL, 然後看到的 Code 是
public interface IOnlyCollection : ICollection, IEnumerable { }
所以單純繼承 ICollection 和 同時繼承 ICollection 與 IEnumerable 意義上根本是一樣的 .
註: 我另外發現這情形在 Visual Basic 的編譯器上似乎不會有相同的情況.
在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
- 已提議為解答 KKBruceMVP 2012年11月20日 上午 01:01
- 已標示為解答 Hans Chen 2012年11月20日 上午 07:04
- 已編輯 Bill ChungMVP, Moderator 2012年11月21日 上午 03:43 Reflector 誤植為 Reflection
-
依照我的認知,介面實作介面的用意並不是要求介面實作,而是要求實作此介面的類別,必須要同時符合原介面以及介面被要求實作的介面。
以 IList 為例,原型是這樣:
interface IList: ICollection { }
而 ICollection 的原型是這樣:
interface ICollection : IEnumerable { }
那麼就相當於:
interface IList : ICollection, IEnumerable { }
編譯器會自動把介面實作介面這件事直接展開到要實作的類別內,例如:
public class ArrayList : IList { .. }
會被展開為:
public class ArrayList : IList, ICollection, IEnumerable {...}
這和什麼介面擴充似乎一點關係也沒有,要說是明確實作也太過牽強了,頂多可說是另一種 compiler magic 吧。
Reference: http://www.roxolan.com/2009/04/interface-inheritance-in-c.html
學習不是查個 Google 套個書上的範例就算了,而是去熟悉了解每個程式碼背後的意義,否則就算學個幾百年,它也不會是你的。
- 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
- 雲端學堂Facebook: http://www.facebook.com/studyazure
- 已提議為解答 KKBruceMVP 2012年11月21日 上午 04:25
- 已標示為解答 Bill ChungMVP, Moderator 2014年5月9日 上午 07:03
所有回覆
-
-
您好,
請參考:Why was the interface IList defined as inheriting the interface IEnumerable twice?
以上說明若有錯誤請指教,謝謝。
亂馬客blog: http://www.dotblogs.com.tw/rainmaker/ -
您好,
請參考:Why was the interface IList defined as inheriting the interface IEnumerable twice?
以上說明若有錯誤請指教,謝謝。
亂馬客blog: http://www.dotblogs.com.tw/rainmaker/我覺得這個說法不通, 你覺得通的道理是在哪 ?
當一個 Interface 繼承自 ICollection 和 IEnumerable 時, 然後我寫一個類別實做這個新的 Interface
不論我把這類別產生的 Instance 轉型為 ICollection 或 IEnumerable, 它執行 GetEnumerator() 的結果都相同.
而且 GetEnumerator() 方法也只能實做一次.
另一個狀況是, 如果我今天做一個新的 Interface , 只繼承 ICollection ,然後建一個新的 Class 來實做這個 Interface,
它的 GetEnumerator() 方法事實上實做的來源還是IEnumerable
或許是我忽略了某些地方以致於混淆了概念, 我沒法認同這篇文章講的理由, 亂馬客可以說說你贊同的理由是什麼嗎 ?
在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
-
如果ICollection有刻意隱藏IEnumerable的方法( new 關鍵字),
然後在實現的class裡面去明確實作兩個介面的同名方法,那才有意義。但我覺得這樣違反了設計邏輯...介面與介面間的繼承應該叫"擴充於",在介面中隱藏母項的合約是很不自然的行為。
這個案例中好像也不是這樣的情況。說真的,要我猜的話,我覺得原因是:
讀程式碼或MSDN或SDK手冊時,明確好讀
看到IList的同時,因為有寫出來,就馬上知道他實現了IEnumerable,而不用再去查ICollection是否擴充於IEnumerable介面。- 已編輯 Litfal 2012年11月19日 上午 08:09
-
您好,
我的想法覺得Interface是一個合約擴充,而非Class的繼承。以上說明若有錯誤請指教,謝謝。
亂馬客blog: http://www.dotblogs.com.tw/rainmaker/ -
您好,
我的想法覺得Interface是一個合約擴充,而非Class的繼承。
以上說明若有錯誤請指教,謝謝。
亂馬客blog: http://www.dotblogs.com.tw/rainmaker/
不論合約擴不擴充, 它的子系用的依然是 IEnumerable 的 GetEnumerator() , 我會寫 Class 的原因只是確認出兩個方式實做出來的東西會一樣.在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
-
我和忠成討論了一下覺得這可能是某些因素造成的:
(1) 一個可能原因是: C# 編譯器在 IL Code 中會將所有Interface 展開, 所以它文件乾脆也攤平寫.
(2) 一個證據是 ArrayList 的 Source Code 中其實它是這樣宣告的
public class ArrayList : IList, ICloneable
但是在文件庫上的寫法也是整個攤開變成
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
(3) 所以當你從 IL Code 反解回原始碼, 它就順勢被攤平. 所以我做了一個實驗
我先寫一個類別庫的專案, 裡面寫了一個 Interface
public interface IOnlyCollection:ICollection { }
然後我將這個類別庫編譯完成後, 用 Reflector 去開啟這個 DLL, 然後看到的 Code 是
public interface IOnlyCollection : ICollection, IEnumerable { }
所以單純繼承 ICollection 和 同時繼承 ICollection 與 IEnumerable 意義上根本是一樣的 .
註: 我另外發現這情形在 Visual Basic 的編譯器上似乎不會有相同的情況.
在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
- 已提議為解答 KKBruceMVP 2012年11月20日 上午 01:01
- 已標示為解答 Hans Chen 2012年11月20日 上午 07:04
- 已編輯 Bill ChungMVP, Moderator 2012年11月21日 上午 03:43 Reflector 誤植為 Reflection
-
以下是小弟的淺見,
以IList:ICollection, IEnumerable來看
表示如果您實作IList的話,就要實作IList, ICollection及IEnumerable的interface。所以從interface的實作來看,IList:ICollection, IEnumerable就不覺得奇怪了。
MSDN文件中說的並不是IList還要繼承IEnumerable介面,而是說要讓實作的Class知道他要實作那些介面,或許文件是用程式產生出來的,所以讓人有IList還要繼承IEnumerable介面的誤解。
所以在Class實作IList時,會有2個實作選項,實作介面'IList'(I) 及 明確實作介面'IList'(X)。
如下圖所示。
以上說明若有錯誤請指教,謝謝。
亂馬客blog: http://www.dotblogs.com.tw/rainmaker/- 已編輯 亂馬客 2012年11月22日 上午 10:36
-
依照我的認知,介面實作介面的用意並不是要求介面實作,而是要求實作此介面的類別,必須要同時符合原介面以及介面被要求實作的介面。
以 IList 為例,原型是這樣:
interface IList: ICollection { }
而 ICollection 的原型是這樣:
interface ICollection : IEnumerable { }
那麼就相當於:
interface IList : ICollection, IEnumerable { }
編譯器會自動把介面實作介面這件事直接展開到要實作的類別內,例如:
public class ArrayList : IList { .. }
會被展開為:
public class ArrayList : IList, ICollection, IEnumerable {...}
這和什麼介面擴充似乎一點關係也沒有,要說是明確實作也太過牽強了,頂多可說是另一種 compiler magic 吧。
Reference: http://www.roxolan.com/2009/04/interface-inheritance-in-c.html
學習不是查個 Google 套個書上的範例就算了,而是去熟悉了解每個程式碼背後的意義,否則就算學個幾百年,它也不會是你的。
- 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
- 雲端學堂Facebook: http://www.facebook.com/studyazure
- 已提議為解答 KKBruceMVP 2012年11月21日 上午 04:25
- 已標示為解答 Bill ChungMVP, Moderator 2014年5月9日 上午 07:03
-
以下是來自 .NET Framework Reference Source Code 中的 ArrayList 宣告:
public class ArrayList : IList, ICloneable { ... }
證實了我上面的論點。
學習不是查個 Google 套個書上的範例就算了,而是去熟悉了解每個程式碼背後的意義,否則就算學個幾百年,它也不會是你的。
- 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
- 雲端學堂Facebook: http://www.facebook.com/studyazure