ハンスの答えに照らした新しい答え
ハンスの答えのおかげで、実装が思ったよりもやや複雑であることがわかります。コンパイラーとCLRの両方が、配列型が実装しているような印象を与えるために非常に一生懸命に努力しますIList<T>
が、配列の違いにより、これがさらに難しくなります。Hansの回答とは逆に、特定の配列の型はそうではない ため、配列型(とにかく1次元、ゼロベース)は、ジェネリックコレクションを直接実装します。これは配列の基本型にSystem.Array
すぎません。配列型にサポートするインターフェイスを尋ねると、一般的な型が含まれます。
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
出力:
System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
1次元のゼロベースの配列の場合、言語に関する限り、配列も実際に実装されIList<T>
ます。C#仕様のセクション12.1.2はそう述べています。したがって、基礎となる実装が行うことは何でも、言語は、他のインターフェイスと同様に、実装のタイプのように動作する必要があります。この観点から、インターフェースは、明示的に実装されているメンバーの一部(など)を使用して実装されます。これが、言語レベルで何が起こっているかを説明する最良の説明です。T[]
IList<T>
Count
これは、1次元配列(およびゼロベースの配列)にのみ当てはまることに注意してください。言語としてのC#は、非ゼロベースの配列については何も述べていません。実装T[,]
していませんIList<T>
。
CLRの観点から見ると、もっとおかしなことが起こっています。ジェネリックインターフェイスタイプのインターフェイスマッピングは取得できません。例えば:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
例外を与えます:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
ではなぜ奇妙なのでしょうか?まあ、それは本当に配列の共分散によるものだと思います。これは型システムIMOのいぼです。にもかかわらずIList<T>
ではない(かつ安全にすることはできません)共変、配列の共分散は、仕事にこれを許可します。
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... 実際にはそうではないときに、それを実装のように見せます。typeof(string[])
IList<object>
CLI仕様(ECMA-335)パーティション1、セクション8.7.1には次の内容があります。
署名タイプTは、以下の少なくとも1つが成り立つ場合に限り、署名タイプUと互換性があります。
...
Tは、ゼロベースのランク1配列でV[]
あり、U
でありIList<W>
、そしてVは、アレイ素子互換-とWです。
(これは、実際には言及していないICollection<W>
か、IEnumerable<W>
私は仕様のバグであると考えています。)
非差異の場合、CLI仕様は言語仕様と直接連動します。パーティション1のセクション8.9.1から:
さらに、エレメントタイプTで作成されたベクターは、インターフェイスを実装しますSystem.Collections.Generic.IList<U>
。ここで、U:= Tです(§8.7)。
(ベクトルは、底がゼロの1次元配列です。)
今の観点から実装の詳細、明確にCLRは、ここに代入互換性を維持するために、いくつかのファンキーなマッピングを行っている次の場合string[]
の実施を求めているICollection<object>.Count
、それがでていることを扱うことができない非常に通常の方法。これは明示的なインターフェース実装としてカウントされますか?インターフェイスマッピングを直接要求しない限り、言語の観点からは常にそのように動作するので、そのように扱うことは合理的だと思います。
どうICollection.Count
ですか?
ここまでは、ジェネリックインターフェイスについて説明してきましたが、ICollection
そのCount
プロパティを持つ非ジェネリックもあります。今回はインターフェースのマッピングを取得できますSystem.Array
。実際、インターフェースはによって直接実装されています。ICollection.Count
プロパティ実装のドキュメントには、Array
明示的なインターフェース実装で実装されていると記載されています。
この種の明示的なインターフェースの実装が「通常の」明示的なインターフェースの実装とは異なる方法を誰かが考えることができるなら、私はそれをさらに調査したいと思います。
明示的なインターフェース実装に関する古い答え
上記にもかかわらず、配列の知識のためにさらに複雑ですが、明示的なインターフェイスの実装を通じて、同じ目に見える効果を使って何かを行うことができます。
次に、簡単なスタンドアロンの例を示します。
public interface IFoo
{
void M1();
void M2();
}
public class Foo : IFoo
{
// Explicit interface implementation
void IFoo.M1() {}
// Implicit interface implementation
public void M2() {}
}
class Test
{
static void Main()
{
Foo foo = new Foo();
foo.M1(); // Compile-time failure
foo.M2(); // Fine
IFoo ifoo = foo;
ifoo.M1(); // Fine
ifoo.M2(); // Fine
}
}
Array
クラスをC#で記述する必要があるとは誰も言っていません。