某天,同事小新問我一個關於 C# 接口繼承的有趣問題:System.Collections.CollectionBase 類別繼承自 IList、ICollection 和 IEnumerable,而 IList 本身已繼承 ICollection 和 IEnumerable,那麼 CollectionBase 為什麼還要顯式聲明實現 ICollection 和 IEnumerable 呢?
我們先看 MSDN 文檔中的聲明結構:
public interface IEnumerable
public interface ICollection : IEnumerable
public interface IList : ICollection, IEnumerable
public abstract class CollectionBase : IList, ICollection, IEnumerable
根據接口繼承規則,實現 IList 就必須實現 ICollection,進而必須實現 IEnumerable。那麼,顯式列出所有介面是否有實質意義?
換句話說,下面兩種聲明在編譯層面沒有區別:
// 方式一:顯式列出所有介面
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
// 方式二:僅聲明最底層介面
public class ArrayList : IList, ICloneable
為了驗證猜測,我分別詢問了 C# 編譯器團隊的 Eric Gunnerson 和 BCL 團隊的 Kit George。
Eric Gunnerson 回覆:
"I think that readability would be the primary reason people would do this."
Kit George 回覆:
"Allen, what you're seeing is simply a doc thing. ArrayList actually only implements IList directly, but we decided in V1.0 of the docs, to highlight the interface hierarchy so you didn't have to wonder 'what does IList implement', you get to see it there on the type.
There is no benefit to ACTUALLY doing this."
Kit 還提供了一段測試代碼證明編譯器允許簡寫聲明:
using System;
using System.IO;
public class Test : IBob2
{
void IBob.M() {}
}
interface IBob
{
void M();
}
interface IBob2 : IBob {}
查看微軟 Rotor 源碼發現 ArrayList 採用方式一(顯式列出),而 Mono(v1.1.2)則採用方式二(精簡聲明)。
這純粹是為了提高代碼可讀性和文檔的自說明性。在實際開發中,兩種寫法編譯結果完全一致,下次遇到類似情況,你可以自信地說:「這只是為了讓介面層級一目瞭然!」