[翻訳]Listはなぜそんなに多くのインターフェースを実現しましたか?


[翻訳]Listはなぜ多くのインターフェースを実現しましたか?
原文の住所:http://blogs.msdn.com/b/ericlippert/archive/2011/04/04/so-many-interfaces.aspx
原作者:エリックLippert
エリックLippertはマイクロソフトの社員で、C〓コンパイラの主な開発者の一人です.
 
今日はStockOverflowで質問に答えました.これまでの習慣で、会話体としてブログにまとめました.
MSDNの文書で、List<T>はこう宣言されています.
public class List : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
 
では、Listは本当にこんなに多くのインターフェースを実現しましたか?
はい、そうです
なぜこんなに多くのインターフェースがありますか?
例えば、IList<T>がIEnumerable<T>から派生している場合、派生度の高いインターフェースの実現者は、派生度の低いインターフェースを実現しなければならない.インターフェース継承はこのようなものです.派生度の高いタイプの契約を満たすには、派生度の低いタイプを満たす必要があります.
つまり、一つのクラスまたは一つのstructは、その伝達閉ループのすべてのインターフェースで定義されるすべての方法を実現しなければならないということですか?
とても正確です
派生度の高いインターフェースを実現したclassまたはstructは、それらの派生度の低いインターフェースを実現したとそのベースタイプリストに宣言しなければならないですか?
いいえ.
それは禁止声明になりますか?
できません
派生レベルが低いインターフェースは、ベースリストの中でオプションとして宣言されていますか?
はい、そうです
いつもそうですか?
基本的にはいつもそうです.
interface I1 {}
interface I2 : I1 {}
interface I3 : I2 {}
 
I 3が明示的に示されているかどうかは、I 1が任意であることを実現している.
class B : I3 {}
 
I 3の実現者はI 2とI 1を実現しなければならないが、明示的に指定する必要はない.指定するかどうかは選択できます.
class D : B {}
派生類は基本的なインターフェースを実現していると指定できますが、必ずしもそうする必要はありません.
次の例があります.
class C<T> where T : I3
{
  public virtual void M<U>() where U : I3 {}
}
 
 
TとUに対応するタイプのパラメータはI 2とI 1を実装しなければならないが、TのUの一般的なタイプの制約には明示的に指定する必要はない.
分布クラスでは、実装されたインターフェースを再宣言するかどうかもオプションです.
partial class E : I3 {}
partial class E {}
 
タイプEの第二部分は、I 3、I 2またはI 1が実現されたと宣言してもよいが、必ずしもそうする必要はない.
はい、分かりました.これはオプションです.なぜ誰かが声明したいインターフェースがありますか?
コードを読みやすくして説明性があると考えているからでしょう.
ある開発者が次のコードを書く可能性があります.
interface I1 {}
interface I2 {}
interface I3 : I1, I2 {}
 
そして彼は、I 2がI 1から継承されるべきであることに気づいた.なぜ開発者にI 2をI 1から継承するように修正した後、I 3の声明からI 1の継承を削除してもらう必要がありますか?私は何の理由も見つけられません.開発者に冗長な声明情報を削除させるよう強制します.
読みやすさと分かりやすさの他に、一つのインターフェースと宣言しないが、このインターフェースを実現するにはどのような技術的な違いがありますか?
普通はありませんが、場合によっては少し違っています.Dタイプがあると仮定して、その基本クラスBはいくつかのインターフェースを実現した.DはBを通しても自動的にそのインターフェースを実現します.これらのインターフェースがDベースリストで明示的に宣言されているなら、C〓コンパイラはインターフェースを再実現します.その詳細はやや晦渋である.これに興味があるなら、Cの言語規範の13.4.6をよく読むことをお勧めします.基本的にコンパイラは「再スタート」します.どの方法がどのインターフェースを実現しているのかを探してください.
List<T>のソースコードの中で、そんなに多くのインターフェースが明示的に宣言されていますか?
いいえ、ちがいます.本当のソースコードはこうです.
public class List<T> : IList<T>, System.Collections.IList
ソースコードは明示的にすべてのインターフェースを宣言していませんが、MSDNはやはりすべてのインターフェースを並べましたか?
MSDNは文書ですので、できるだけ多くの情報を提供するべきです.ページのドキュメントで完全な情報を提供するのは、ドキュメントを十ページめくるよりも、一つのタイプの実現されたすべてのインターフェースの方がいいです.
なぜ一部のツールがありますか?例えば、Reflecttorやオブジェクトブラウザはすべてのインターフェースを表示しますか?
これらのツールはソースコードがどうなっているか分かりません.メタデータからしか入手できません.明示的な声明はすべてのインターフェースがオプションであるため、これらのツールはソースコードが明示的にすべてのインターフェースを宣言しているかどうかを全く知ることができません.いくら表示しても間違っている可能性があります.これらのツールは情報を全部羅列したほうがいいです.これらのツールは、実際の状況よりも多くの情報を表示します.あなたに必要な情報を隠すのではなく、あなたを助けたいからです.
IEnumerable<T>はIEnumerableから継承されていることが分かりましたが、IList<T>はIListから継承されていません.これはどういうことですか?
これはIEnumerable<T>と協働していますが、IList<T>が協働していないのが原因です.箱に詰めることによって、我々は一つの整数系列を一つのobjectのシーケンスとして扱うことができます.しかし、読み書き可能な整数リストは、読み書き可能なobjectのリストとして扱われてはいけません.これは、読み書き可能なobjectリストにStringを追加することができるからです.IEnumerable<T>を実現するタイプは簡単にIEnumerableを満足することができます.箱詰めのhelper方法を追加すればいいです.しかし、IList<T>を実現するタイプは必ずしもIListを満足させるとは限らないので、IListはIListから引き継がれていない.
どうしてList<T>はまたIListを実現したのですか?
これはちょっとおかしいです.Tがobjectの時以外はList<T>が満足できないIListの要求です.これは古いC〓のコードをアップグレードしたい人に便宜を図るためかもしれないでしょう.彼らが普通型を使いやすいようにします.コードをアップグレードしたい人は、リストに正しいタイプのオブジェクトだけを追加することができます.また、多くの場合、1つのIListをパラメータとして渡す場合、呼び出しられた方法は、リストに任意の種類のオブジェクトを追加するのではなく、インデックスに従ってリストにアクセスするだけである.