早速の回答ありがとうございます。

いただいた回答をもとに色々考えましたが、何か釈然としない部分が残っています。

先のコードの、
IEnumerator i = collection.GetEnumerator(); // @
i.MoveNext() // A
の部分は、下記のような動作と考えていいのでしょうか?

@について:
・collectionはMyCollection<int>型である。
・よって、collection.GetEnumerator()のGetEnumerator()はジェネリック版のほうを意味し、
 その戻り値はIEnumerator<T>型である。
・IEnumerator<T>型である戻り値が、IEnumerator型の変数iに入る。
・IEnumerator<T>型の値を、IEnumerator型の変数に入れられる理由は、
 「IEnumerator<>はIEnumeratorを継承しているから」。

Aについて:
・i.MoveNext()により、実際にGetEnumerator()が呼ばれる。
・iはIEnumerator型(非ジェネリック)であるが、i.MoveNext()で実際に呼ばれるのは、
 ジェネリック版のGetEnumerator()のほう。

以上の動作は、
インターフェイスI1をI2が継承するとして、
I2型の値をI1型の変数に入れて、I1型の変数経由で、I2にしかないメソッドを呼んでいるように見えます。
(I2にしかないメソッドとは、今回の例ではジェネリック版GetEnumerator()のことです)

== 続く ==