このインターフェースをより詳細に調べるために、私は最初に宣言するメソッドを確認することにしました。 反射を使用する:
foreach(var tp in typeof(IList).GetMembers()) Console.WriteLine(tp.Name);
...次の結果が得られました。
get_Item set_Item Add Contains Clear get_IsReadOnly get_IsFixedSize IndexOf Insert Remove RemoveAt Item IsReadOnly IsFixedSize
簡単に推測できるように、プレフィックスはインターフェイスプロパティのゲッターとセッターを示しています。 すべてのメソッドに加えて、さらに3つのプロパティがあります。書き込みおよび読み取り機能を持つアイテムと、2つのreodonlyプロパティIsReadOnlyおよびIsFixedSizeです。 さらに、名前のあいまいな重複が顕著です:get_IsReadOnly // IsReadOnly、get_IsFixedSize // IsFixedSize、get_Item // set_Item // Item。 これに対処するために、コードを少し変更する必要があり、クラスのプロパティ自体に加えて、プロパティのタイプの名前も出力する必要がありました。 次のコードが判明しました。
foreach(var tp in typeof(IList).GetMembers()) Console.WriteLine("{0} -- {1}", tp.Name, Enum.GetName(tp.MemberType.GetType(), tp.MemberType));
このコードにより、より詳細なアイデアが得られました。 インターフェースに含まれるもの:
get_Item -- Method set_Item -- Method Add -- Method Contains -- Method Clear -- Method get_IsReadOnly -- Method get_IsFixedSize -- Method IndexOf -- Method Insert -- Method Remove -- Method RemoveAt -- Method Item -- Property IsReadOnly -- Property IsFixedSize -- Property
そのため、get_IsFixedSizeがIsFixedSizeプロパティが読み取られたときに呼び出されるメソッドであるように、get_IsReadOnlyはIsReadOnlyプロパティ(メソッドとは別のインターフェイスのメンバー)の取得メソッドであることが明らかになりました。 ここのItemプロパティには、セッターとゲッターの両方があります。つまり、まるでそれを読んでいるかのようにアクセスできます。 そして変化します。
これを実現するために、私はすぐに疑問に思いました。プロパティのメソッドが既に事前定義されている場合はどうなるのでしょうか。
最初の例をすばやく作成して、私は確信しました。 そのようなコードはコンパイルされません:
public class Test1 { public int A { get; set; } public int get_A() { return 0; } }
コンパイラは次のエラーを生成します。
Type 'TestArray.Test1' already reserves a member called 'get_A' with the same parameter types
Itemの2番目のプロパティは、より興味深いことが判明しました。 インデクサーが同じ名前のプロパティの背後に隠れているという私の考えは真実であることが判明し、今回はインデクサーを使用して、2番目の未コンパイルのクラスを作成できました。
public class Test2 { public int Item { get; set; } public int this[int num] { get { return 0; } } }
今回はエラーの説明が少し異なりましたが、問題の本質も明らかでした。
The type 'TestArray.Test2' already contains a definition for 'Item'
ただし、インデクサーが必要とするメソッドを明示的に実装することでコンパイラを「トリック」しようとする逆の試みは失敗しました。 問題なくコンパイルされた次の2つのサンプルクラス、
public class Test4 { public int Item { get; set; } } public class Test3 { public Test3 get_Item(int index) { return this; } public void set_Item(int index, Test3 value) { } }
ただし、インデクサーを使用してクラスインスタンスにアクセスしようとすると、コンパイルエラーが発生しました。
Cannot apply indexing with [] to an expression of type 'TestArray.Test4'
そのように。 コンパイラーは、コンパイル時にインデクサーの構文をチェックします。これにより、このようなトリッキーな方法を使用して独自のインデクサーを判別できなくなります。
小規模な調査から、次の結論が導き出されます。
- C#コンパイラは、インデクサーやプロパティセッター/ゲッターなどの構文的に「シュガー」コンストラクトを使用する場合、かなりシンプルで明白なアルゴリズムを使用して内部メソッドの名前を生成します。
- メソッドの複雑な名前を考案しなくても、名前の衝突の問題が発生する可能性があります。これは、.Net内部デバイスの詳細を知らないと理解しにくいものです。
- Itemプロパティとそれに対応するセッターとゲッターは、コンパイラによって、後置演算子「角括弧」(=インデクサー)の構文に変換されます。これは、get_Item()構文の構文糖です。
記事が楽しい場合。 次の記事では、IListインターフェースに興味のあることを説明します。